# TO DO
# - Framework for quantifying the effects of within- and across-population variation in thermal limits to spatial patterns in vulnerability to warming. Comparing predictions based on 1) median, 2) overall CTmax vs. temp regression, 3) population variation in intercepts, 4) population variation in both slope and intercept. The end metric I could use to compare across scenarios is i) the cumulative amount of underestimation (summed across populations) or ii) the number of sites that have overestimated WT, or iii) the slope of WT (local adaptation and seasonal acclimation should result in more shallow slopes).
Site Characteristics
site_temps = full_data %>%
dplyr::select(site, lat, season, doy, collection_temp, collection_salinity) %>%
distinct() %>%
filter(doy > 100)
Copepods were collected by surface tow from sites across the Western
Atlantic at several times throughout the year. The sites are shown
below. Temperatures at the time of collection were measured using a
manual thermometer. Across the entire set of collections, temperature
ranged from 10°C to 36°C.
coords = site_data %>%
dplyr::select(site, long, lat) %>%
distinct()
site_map = map_data("world") %>%
filter(region %in% c("USA", "Canada")) %>%
ggplot() +
geom_polygon(aes(x = long, y = lat, group = group),
fill = "lightgrey") +
coord_map(xlim = c(-85,-60),
ylim = c(25, 48)) +
geom_point(data = coords,
mapping = aes(x = long, y = lat, colour = site),
size = 3) +
scale_colour_manual(values = site_cols) +
labs(x = "Longitude",
y = "Latitude") +
theme_matt(base_size = 16)
site_temp_plot = ggplot(site_temps, aes(x = doy, y = collection_temp, colour = site)) +
geom_line(linewidth = 2) +
geom_point(size = 5) +
scale_colour_manual(values = site_cols) +
labs(y = "Temperature (°C)",
x = "Day of the Year") +
theme_matt() +
theme(legend.position = "right")
ggarrange(site_map, site_temp_plot, common.legend = T, legend = "bottom")

Collections aimed to obtain copepods near the onset of peak
temperatures, after peak temperatures, and then at low temperatures.
Regional data is not available for all sites, so here we’ve pieced
together daily temperature values from either local temperature sensors
(sites in Florida and the Chesapeake) and high resolution satellite
temperature data (Connecticut, Maine, and the Canadian sites). This
satellite data comes from the NOAA 1/4° Daily Optimum Interpolation Sea
Surface Temperature (OISST).
These temperature profiles are shown below, with the temperatures
measured during the time of collection included for comparison In
several cases collection temperature does not match the recorded daily
averages, but the temperature records do give a general sense of the
timing of seasonal maxima. In general, the first sample from each site
fell just after the site reached the warmest period. The exception to
that pattern is in Florida, where collections occurred after an extended
period of high temperatures.
temp_profiles = temp_profiles %>%
mutate(region = fct_relevel(region, "Florida", "Chesapeake", "Connecticut",
"Maine", "Shediac", "Miramichi"))
site_temps2 = site_temps %>%
mutate(region = case_when(
site == "Manatee River" ~ "Florida",
site == "Ft. Hamer" ~ "Florida",
site == "Tyler Cove" ~ "Chesapeake",
site == "Ganey's Wharf" ~ "Chesapeake",
site == "Esker Point" ~ "Connecticut",
site == "Sawyer Park" ~ "Maine",
site == "St. Thomas de Kent Wharf" ~ "Shediac",
site == "Ritchie Wharf" ~ "Miramichi"),
region = fct_relevel(region, "Florida", "Chesapeake", "Connecticut",
"Maine", "Shediac", "Miramichi"))
ggplot(temp_profiles, aes(x = doy, y = temp_c)) +
facet_wrap(region~.) +
geom_point(data = site_temps2,
aes(x = doy, y = collection_temp, colour = site),
size = 3) +
geom_line() +
scale_colour_manual(values = site_cols) +
labs(x = "Day of the Year",
y = "Mean Daily Temp. (°C)") +
theme_matt_facets() +
theme(legend.position = "none")

Exact locations for the sites are provided here.
site_data %>%
arrange(lat) %>%
select("Site" = site, "Region" = region, "Lat" = lat, "Long" = long) %>%
knitr::kable(align = "c")
| Key Largo |
Florida |
25.28391 |
-80.33014 |
| Manatee River |
Florida |
27.50561 |
-82.57277 |
| Ft. Hamer |
Florida |
27.52488 |
-82.43101 |
| Tyler Cove |
Maryland |
38.35083 |
-76.22902 |
| Ganey’s Wharf |
Maryland |
38.80555 |
-75.90906 |
| Esker Point |
Connecticut |
41.32081 |
-72.00166 |
| Sawyer Park |
Maine |
43.90698 |
-69.87179 |
| St. Thomas de Kent Wharf |
New Brunswick |
46.44761 |
-64.63692 |
| Ritchie Wharf |
New Brunswick |
47.00481 |
-65.56291 |
Nested within each of the three regions (South, Central, and Northern
regions) are pairs of low and high salinity sites:
data.frame("Region" = c("South", "Central", "North"),
"Low Salinity" = c("Ft. Hamer", "Ganey's Wharf", "Ritchie Wharf"),
"High Salinity" = c("Manatee River", "Tyler Cove", "St. Thomas de Kent Wharf")) %>%
knitr::kable(align = "c")
| South |
Ft. Hamer |
Manatee River |
| Central |
Ganey’s Wharf |
Tyler Cove |
| North |
Ritchie Wharf |
St. Thomas de Kent Wharf |
There are fairly well-established divergences between high salinity
and low salinity populations of Acartia tonsa. These sets of
geographically proximate but isolated populations provide independent
comparisons of the effects of seasonality. Shown here are the collection
conditions for these pairs of sites. Temperature was typically similar
across the pairs within each collection, while salinity differences were
fairly stable across collections.
season_cols = c("early" = "grey75",
"peak" = "grey50",
"late" = "grey25")
sal_regions = data.frame(region = rep(c("South", "Central", "North"), each = 2),
site = c("Ft. Hamer", "Manatee River",
"Ganey's Wharf", "Tyler Cove",
"Ritchie Wharf", "St. Thomas de Kent Wharf"),
salinity = c("low", "high"))
sal_comps = full_data %>%
filter(site %in% sal_regions$site) %>%
inner_join(sal_regions, by = c("site")) %>%
select( region = region.y, site, salinity, season, doy, collection_temp, collection_salinity,
size, ctmax, warming_tol) %>%
mutate(salinity = fct_relevel(salinity, "low", "high"),
region = fct_relevel(region, "South", "Central", "North"))
sal_comp_temps = sal_comps %>%
select(salinity, season, region, collection_temp, collection_salinity) %>%
distinct() %>%
ggplot(aes(x = salinity, y = collection_temp, colour = season, group = season)) +
facet_wrap(region~.) +
geom_line(linewidth = 1.5) +
geom_point(size = 4) +
scale_colour_manual(values = season_cols) +
labs(y = "Collection Temp. (°C)",
x = "") +
theme_matt_facets(base_size = 14)
sal_comp_sal = sal_comps %>%
select(salinity, season, region, collection_temp, collection_salinity) %>%
distinct() %>%
ggplot(aes(x = salinity, y = collection_salinity, colour = season, group = season)) +
facet_wrap(region~.) +
geom_line(linewidth = 1.5) +
geom_point(size = 4) +
scale_colour_manual(values = season_cols) +
labs(y = "Collection Salinity (psu)",
x = "Salinity") +
theme_matt_facets(base_size = 14)
ggarrange(sal_comp_temps, sal_comp_sal, nrow = 2, common.legend = T, legend = "right")

# sal_comps %>%
# select(site, salinity, season, region, collection_temp, collection_salinity) %>%
# distinct() %>%
# ggplot(aes(x = collection_salinity, y = collection_temp, colour = site)) +
# facet_grid(region~.) +
# geom_point(size = 4) +
# #stat_ellipse() +
# #geom_path(arrow = arrow(length = unit(0.1, "inches"), type = "closed")) +
# scale_colour_manual(values = site_cols) +
# theme_matt_facets(base_size = 14)
The latitudinal gradient covers a wide range of seasonality. Shown
below is the temperature range. While based on collection temperatures,
and therefore an underestimate of the total seasonal range of
temperatures, these patterns are representative of the expected
latitudinal gradient in seasonality.
site_temps %>%
group_by(site, lat) %>%
summarise(temp_range = max(collection_temp) - min(collection_temp)) %>%
ggplot(aes(x = lat, y = temp_range)) +
geom_point(aes(colour = site),
size = 3) +
scale_color_manual(values = site_cols) +
labs(x = "Latitude",
y = "Collection Temp. Range (°C)") +
theme_matt() +
theme(legend.position = "right")

Phenotypic Measurements
Critical Thermal Limits
A total of 456 individuals were examined. Critical thermal limits and
body size measurements were made before individuals were preserved in
ethanol. We excluded data for 7 individuals, detailed below. These
individuals had either very low CTmax or were, upon re-examination of
photographs, identified as juveniles instead of mature females. With
these individuals excluded, the full data set contains 449
phenotyped individuals.
excluded %>%
select(region, site, season, collection_temp, collection_salinity, replicate, tube, ctmax, size) %>%
knitr::kable(align = "c")
| Florida |
Manatee River |
peak |
34.0 |
29 |
2 |
6 |
38.45833 |
0.616 |
| Florida |
Manatee River |
peak |
34.0 |
29 |
2 |
7 |
38.23750 |
0.593 |
| Florida |
Ft. Hamer |
late |
20.0 |
18 |
2 |
3 |
36.59280 |
0.619 |
| Maryland |
Tyler Cove |
peak |
29.5 |
15 |
2 |
2 |
36.84375 |
0.614 |
| Connecticut |
Esker Point |
early |
22.5 |
30 |
2 |
3 |
30.02604 |
0.687 |
| Maine |
Sawyer Park |
peak |
22.0 |
30 |
1 |
4 |
30.81424 |
0.865 |
| New Brunswick |
St. Thomas de Kent Wharf |
late |
13.5 |
28 |
1 |
3 |
28.78299 |
1.039 |
Critical thermal maxima (CTmax) was measured using a custom setup.
The method uses a standard dynamic ramping assay to determine the
maximum temperature individuals could sustain normal functioning. This
differs from lethal temperatures, and indeed, all individuals observed
so far recovered following the assay.
Individuals were rested for one hour after collection before the
assay. During the assay, copepods were held in artificial seawater,
composed of bottled spring water and Instant Ocean salt mix adjusted to
match collection salinities. During the assay, several ‘control’
individuals were maintained in this solution at ambient temperatures
without the temperature ramp to ensure that there was no background
mortality. When sorting individuals from the plankton tow contents, they
were held in a 50:50 mix of 60 um filtered water from the collection
site and artificial seawater as an additional acclimation step.
Sample sizes varied slightly across experiments, but most sites had
20 individuals measured per season. The major exceptions were the early
samples from the Florida sites and the late sample from Sawyer Park
(Maine). Only two sets of samples (peak and late) were collected from
Fort Hamer and Manatee River. No samples were collected from Key Largo
for this project, as Acartia tonsa wasn’t present in the water
during the peak season, likely due to the recent extreme heat event. The
late season collection from Sawyer Park occurred after Acartia
tonsa abundance decreased. Samples from this period were dominated
by Acartia hudsonica instead.
ggplot(full_data, aes(x = site, fill = site)) +
facet_wrap(season~.) +
geom_hline(yintercept = c(0,20),
colour = "grey70") +
geom_bar() +
scale_fill_manual(values = site_cols) +
coord_flip() +
theme_matt() +
theme(legend.position = "none",
panel.border = element_rect(linewidth = 1,
fill = NA),
strip.text = element_text(size = 20),
axis.title.y = element_blank())

Shown below are the measured CTmax values. Note: CTmax values for the
early season Key Largo copepods were collected at the end of February
2023 as part of a separate project. Body size values were not measured
during this project, nor were copepods individually preserved after the
experiments. These early season CTmax values are included as a point of
comparison. Individual measurements are shown in small points for each
collection. The large points indicate the mean values for each
collection.
mean_ctmax = full_data %>%
group_by(site, season, doy, collection_temp) %>%
summarize(mean_ctmax = mean(ctmax),
median_ctmax = median(ctmax))
ggplot(full_data, aes(x = season, y = ctmax, colour = site)) +
geom_line(data = mean_ctmax,
aes(y = mean_ctmax, group = site),
position = position_dodge(width = 0.4),
linewidth = 1) +
geom_point(position = position_jitterdodge(jitter.width = 0.1, jitter.height = 0,
dodge.width = 0.4),
alpha = 0.3) +
geom_point(data = mean_ctmax,
aes(y = mean_ctmax),
position = position_dodge(width = 0.4),
size = 4) +
scale_colour_manual(values = site_cols) +
labs(y = "CTmax (°C)",
x = "Season") +
theme_matt() +
theme(legend.position = "right",
legend.title.align = 0.125)

CTmax data for each individual site is shown below, plotted against
day of the year.
ggplot(full_data, aes(x = doy, y = ctmax, colour = site)) +
facet_wrap(.~site, scales = "free") +
geom_line(data = mean_ctmax,
aes(y = mean_ctmax, group = site),
position = position_dodge(width = 0.4),
linewidth = 3, alpha = 0.5) +
# geom_line(data = mean_ctmax,
# aes(y = collection_temp, group = site),
# position = position_dodge(width = 0.4),
# linewidth = 2,
# colour = "grey") +
geom_point(position = position_jitterdodge(jitter.width = 0.1, jitter.height = 0,
dodge.width = 0.4),
alpha = 0.8) +
# geom_point(data = mean_ctmax,
# aes(y = median_ctmax),
# position = position_dodge(width = 0.4),
# size = 4) +
scale_colour_manual(values = site_cols) +
labs(y = "CTmax (°C)",
x = "Day of Year") +
theme_matt() +
theme(legend.position = "none",
legend.title.align = 0.125)

Warming tolerance
Warming tolerance (the difference between thermal limits and
environmental temperatures) is a commonly used metric of climate
vulnerability. We calculated this as the difference between measured
CTmax values and the collection temperature. Smaller warming tolerance
values indicate that populations were nearer to their upper thermal
limits, and may therefore be more vulnerable to additional warming.
mean_wt = full_data %>%
group_by(site, season) %>%
summarize(mean_wt = mean(warming_tol),
median_wt = median(warming_tol))
ggplot(full_data, aes(x = season, y = warming_tol, colour = site)) +
geom_line(data = mean_wt,
aes(y = mean_wt, group = site),
position = position_dodge(width = 0.4),
linewidth = 1) +
geom_point(position = position_jitterdodge(jitter.width = 0.1, jitter.height = 0,
dodge.width = 0.4),
alpha = 0.3) +
geom_point(data = mean_wt,
aes(y = mean_wt),
position = position_dodge(width = 0.4),
size = 4) +
scale_colour_manual(values = site_cols) +
labs(y = "Warming Tolerance (°C)",
x = "Season") +
theme_matt() +
theme(legend.position = "right",
legend.title.align = 0.125)

Body Size
Following the CTmax assay, individuals were photographed for body
size measurements. Prosome lengths were measured from these photographs
using a scale micrometer and the software ImageJ. These measurements are
shown below. As before, large points indicate the mean body size. While
less cohesive than CTmax, a general trend of increasing body size with
latitude and time of year can be seen.
mean_size = full_data %>%
group_by(site, season, doy, collection_temp) %>%
summarize(mean_size = mean(size),
median_size = median(size))
ggplot(full_data, aes(x = season, y = size, colour = site)) +
geom_line(data = mean_size,
aes(y = mean_size, group = site),
position = position_dodge(width = 0.4),
linewidth = 1) +
geom_point(position = position_jitterdodge(jitter.width = 0.1, jitter.height = 0,
dodge.width = 0.4),
alpha = 0.3) +
geom_point(data = mean_size,
aes(y = mean_size),
position = position_dodge(width = 0.4),
size = 4) +
scale_colour_manual(values = site_cols) +
labs(y = "Prosome Length (mm)",
x = "Season") +
theme_matt() +
theme(legend.position = "right",
legend.title.align = 0.125)

Shown below is the body size data for each individual site.
ggplot(drop_na(full_data, size), aes(x = doy, y = size, colour = site)) +
facet_wrap(.~site) +
geom_line(data = drop_na(mean_size, mean_size),
aes(y = mean_size, group = site),
position = position_dodge(width = 0.4),
linewidth = 3, alpha = 0.5) +
geom_point(position = position_jitterdodge(jitter.width = 0.1, jitter.height = 0,
dodge.width = 0.4),
alpha = 0.8) +
# geom_point(data = mean_ctmax,
# aes(y = median_ctmax),
# position = position_dodge(width = 0.4),
# size = 4) +
scale_colour_manual(values = site_cols) +
labs(y = "Prosome Length (mm)",
x = "Day of Year") +
theme_matt() +
theme(legend.position = "none",
legend.title.align = 0.125)

Salinity Pair Comparisons
The three pairs of cross-salinity comparisons do show evidence for
fine-scale trait divergence, although there was no consistent pattern in
the direction or magnitude of differences. CTmax was similar across
sites in the Southern and Central pairs. In the Northern pair, CTmax
tended to be slightly lower for individuals from the low salinity site.
Size was more variable between the paired sites. In the South, low
salinity individuals were consistently smaller than high salinity
individuals, despite the similar temperatures. In the Central pair,
individuals from the low salinity site tended to be slightly larger than
those from the high salinity site, although this varied seasonally.
Sizes tended to be more similar across the collections from the Northern
pair.
sal_comp_ctmax_plot = sal_comps %>%
ggplot(aes(x = salinity, y = ctmax, colour = season, group = season)) +
facet_wrap(region~.) +
geom_point(size = 2,
position = position_dodge(width = 0.2)) +
#geom_line(size = 1.5) +
scale_colour_manual(values = season_cols) +
labs(y = "CTmax (°C)",
x = "") +
theme_matt_facets(base_size = 14)
sal_comp_size_plot = sal_comps %>%
ggplot(aes(x = salinity, y = size, colour = season, group = season)) +
facet_wrap(region~.) +
geom_point(size = 2,
position = position_dodge(width = 0.2)) +
#geom_line(size = 1.5) +
scale_colour_manual(values = season_cols) +
labs(y = "Prosome Length (mm)",
x = "") +
theme_matt_facets(base_size = 14)
ggarrange(sal_comp_ctmax_plot, sal_comp_size_plot, nrow = 2, common.legend = T, legend = "right")

###
sal_comp_ctmax.model = lm(ctmax ~ collection_temp, data = sal_comps)
# summary(ctmax_temp.model)
# car::Anova(ctmax_temp.model)
sal_comp_ctmax_resids = residuals(sal_comp_ctmax.model)
sal_comp_size.model = lm(size ~ collection_temp, data = sal_comps)
# summary(size_temp.model)
# car::Anova(size_temp.model)
sal_comp_size_resids = residuals(sal_comp_size.model)
sal_comp_ctmax_resid_plot = sal_comps %>%
mutate(ctmax_resids = sal_comp_ctmax_resids,
size_resids = sal_comp_size_resids) %>%
ggplot(aes(x = salinity, y = ctmax_resids, colour = season, group = season)) +
facet_wrap(region~.) +
geom_point(size = 2,
position = position_dodge(width = 0.5)) +
#geom_line(size = 1.5) +
scale_colour_manual(values = season_cols) +
labs(y = "CTmax \nResiduals",
x = "") +
theme_matt_facets(base_size = 14)
sal_comp_size_resid_plot = sal_comps %>%
mutate(ctmax_resids = sal_comp_ctmax_resids,
size_resids = sal_comp_size_resids) %>%
ggplot(aes(x = salinity, y = size_resids, colour = season, group = season)) +
facet_wrap(region~.) +
geom_point(size = 2,
position = position_dodge(width = 0.5)) +
#geom_line(size = 1.5) +
scale_colour_manual(values = season_cols) +
labs(y = "Prosome Length \nResiduals",
x = "") +
theme_matt_facets(base_size = 14)
#ggarrange(sal_comp_ctmax_resid_plot, sal_comp_size_resid_plot, nrow = 2, common.legend = T, legend = "right")
Trait Correlations
Regardless of the underlying mechanism (genetic differentiation or
phenotypic plasticity), we expect that collections from warmer waters
should yield copepods with higher thermal limits and smaller body sizes.
Our observations largely fit this expectation, with strong increases in
CTmax at higher temperatures, and a general decrease in prosome lengths
as temperature increased.
ctmax_temp_plot = ggplot(full_data, aes(x = collection_temp, y = ctmax)) +
geom_smooth(method = "lm", se = T,
linewidth = 2,
colour = "grey") +
geom_point(aes(colour = site),
size = 2, alpha = 0.7) +
scale_colour_manual(values = site_cols) +
labs(y = "CTmax (°C)",
x = "Collection Temp. (°C)") +
theme_matt() +
theme(legend.position = "none")
size_temp_plot = ggplot(full_data, aes(x = collection_temp, y = size)) +
geom_smooth(method = "lm", se = T,
linewidth = 2,
colour = "grey") +
geom_point(aes(colour = site),
size = 2, alpha = 0.7) +
scale_colour_manual(values = site_cols) +
labs(y = "Prosome Length (mm)",
x = "Collection Temp. (°C)") +
theme_matt() +
theme(legend.position = "right")
wt_temp_plot = ggplot(full_data, aes(x = collection_temp, y = warming_tol)) +
geom_smooth(method = "lm", se = T,
linewidth = 2,
colour = "grey") +
geom_point(aes(colour = site),
size = 2, alpha = 0.7) +
scale_colour_manual(values = site_cols) +
labs(y = "Warming Tolerance (°C)",
x = "Collection Temp. (°C)") +
theme_matt() +
theme(legend.position = "right")
ggarrange(ctmax_temp_plot, wt_temp_plot, size_temp_plot, common.legend = T, legend = "bottom", nrow = 1)

Shown below are these temperature correlations for each individual
population. Variation in the temperature sensitivity of these traits
appears to vary across populations, with reduced slopes in both the
lowest and the highest latitude populations. Again, we emphasize that
this observed trait variation may stem from either (or both) plastic and
genetic effects. However, these observations provide estimates for
realistic patterns in temperature sensitivity for these populations.
ggplot(full_data, aes(x = collection_temp, y = ctmax)) +
facet_wrap(.~site) +
geom_smooth(method = "lm", se = T,
linewidth = 2,
colour = "grey") +
geom_point(aes(colour = site),
size = 2, alpha = 0.7) +
scale_colour_manual(values = site_cols) +
labs(y = "CTmax (°C)",
x = "Collection Temp. (°C)") +
theme_matt() +
theme(legend.position = "none")

ggplot(full_data, aes(x = collection_temp, y = size)) +
facet_wrap(.~site) +
geom_smooth(method = "lm", se = T,
linewidth = 2,
colour = "grey") +
geom_point(aes(colour = site),
size = 2, alpha = 0.7) +
scale_colour_manual(values = site_cols) +
labs(y = "Prosome Length (mm)",
x = "Collection Temp. (°C)") +
theme_matt() +
theme(legend.position = "none")

One additional correlation of interest is the relationship between
prosome length and CTmax. In many cases, larger body sizes are
associated with cold adaptation/acclimation, and there is a general
trend of decreasing thermal limits with increasing size. Shown below is
the relationship between prosome length and CTmax in our data set.
Individual regression lines for each site are also included - the dark
grey lines in the background represent the ‘universal’ regression for
that site, with individual colored regression lines for each collection.
Across our collections, we see evidence for this relationship, with
larger individuals having lower thermal limits.
universal_size = full_data %>%
ggplot(aes(x = size, y = ctmax)) +
# geom_smooth(data = filter(full_data, ctmax > 31),
# aes(x = size, y = ctmax),
# method = "lm",
# colour = "grey60",
# se = F,
# linewidth = 2) +
geom_smooth(method = "lm", se = T,
linewidth = 2,
colour = "grey70") +
geom_point(aes(colour = site),
size = 2, alpha = 0.7) +
scale_colour_manual(values = site_cols) +
labs(y = "CTmax (°C)",
x = "") +
theme_matt(base_size = 14) +
theme(legend.position = "right",
axis.title.x = element_blank())
pop_size = full_data %>%
ggplot(aes(x = size, y = ctmax, colour = site, group = season)) +
facet_wrap(site~.) +
# geom_smooth(data = filter(full_data, ctmax > 31),
# aes(x = size, y = ctmax),
# method = "lm",
# colour = "grey60",
# se = F,
# linewidth = 2) +
geom_smooth(data = full_data,
aes(x = size, y = ctmax, group = site),
colour = "grey20", method = "lm", se = F) +
geom_point(size = 1.3, alpha = 0.3) +
geom_smooth(method = "lm", se = F,
linewidth = 1) +
scale_colour_manual(values = site_cols) +
scale_x_continuous(breaks = c(0.6, 0.8, 1)) +
labs(y = "CTmax (°C)",
x = "Prosome Length (mm)") +
theme_matt(base_size = 14) +
theme(legend.position = "right")
ggarrange(universal_size, pop_size, common.legend = T, legend = "none", nrow = 2)

This relationship may be affected by changes in temperature at each
site, however, which may affect both body size and thermal limits. If
there is a true mechanistic relationship between body size and thermal
limits, we would expect to see this relationship emerge
within populations or even individual collections.
Shown below is the relationship between CTmax and size residuals,
acquired from regressions of these traits against collection
temperature. This substantially reduces the strength of the apparent
relationship, but there is still a slightly negative overall
relationship, spanning both across-population, within-population, and
even within-collection scales (see the Sawyer Park collections, for
example).
filtered_data = full_data %>%
drop_na(size, ctmax) %>%
mutate(temp_cent = scale(collection_temp, scale = F),
sal_cent = scale(collection_salinity, scale = F),
sal_type = if_else(collection_salinity > 20, "High", "Low"))
ctmax_temp.model = lm(ctmax ~ collection_temp + site, data = filtered_data)
ctmax_resids = residuals(ctmax_temp.model)
size_temp.model = lm(size ~ collection_temp + site, data = filtered_data)
size_resids = residuals(size_temp.model)
universal_resids = filtered_data %>%
mutate(ctmax_resids = ctmax_resids,
size_resids = size_resids)
all_resids = ggplot(universal_resids, aes(x = size_resids, y = ctmax_resids)) +
# geom_smooth(data = filter(full_data, ctmax > 31),
# aes(x = size, y = ctmax),
# method = "lm",
# colour = "grey60",
# se = F,
# linewidth = 2) +
geom_smooth(method = "lm", se = T,
linewidth = 2,
colour = "grey70") +
geom_point(aes(colour = site),
size = 2, alpha = 0.7) +
scale_colour_manual(values = site_cols) +
labs(y = "CTmax Residuals",
x = "") +
theme_matt(base_size = 14) +
theme(legend.position = "right",
axis.title.x = element_blank())
pop_resids = ggplot(universal_resids, aes(x = size_resids, y = ctmax_resids, colour = site, group = season)) +
facet_wrap(site~.) +
# geom_smooth(data = filter(full_data, ctmax > 31),
# aes(x = size, y = ctmax),
# method = "lm",
# colour = "grey60",
# se = F,
# linewidth = 2) +
geom_smooth(aes(x = size_resids, y = ctmax_resids, group = site),
colour = "grey20", method = "lm", se = F) +
geom_point(size = 1.3, alpha = 0.3) +
geom_smooth(method = "lm", se = F,
linewidth = 1) +
scale_colour_manual(values = site_cols) +
labs(y = "CTmax Residuals",
x = "Prosome Length Residuals") +
theme_matt(base_size = 14) +
theme(legend.position = "right")
ggarrange(all_resids, pop_resids, common.legend = T, legend = "none", nrow = 2)

To more formally test the relationships between CTmax, collection
temperature, and size, we used a linear mixed effects model, structured
as
ctmax ~ collection_temp + size + salinity_type + (1|site).
This examines the effects of temperature and size on CTmax, along with
differences between the salinity groupings. Collection temperature was
centered and salinity type assigned (“low” salinity as anything below 20
psu, “high” salinity as anything above 20 psu) before model fitting. The
model also includes random intercepts for each site and random slopes
for collection temperature (i.e. - variation in the acclimation capacity
of CTmax).
Collection temperature and body size both had a significant effect on
CTmax, but salinity type did not. The overall effect of temperature
suggests an increase in CTmax of 0.2°C per °C increase in collection
temperature (i.e. - an ARR value of 0.2), while increasing body sizes
decrease CTmax by -3.15°C per mm (or a decrease of ~-0.315°C per tenth
of a mm, which is more biologically realistic for A. tonsa).
While not significant, the model suggests low salinity sites had lower
thermal limits by ~1°C.
#summary(ctmax.model)
effects_summary = data.frame(
"Temperature" = unname(fixef(ctmax.model)["temp_cent"]),
"Size" = unname(fixef(ctmax.model)["size"]),
"Salinity" = unname(fixef(ctmax.model)["sal_typeLow"]))
knitr::kable(effects_summary)
| 0.195262 |
-3.153573 |
-1.041622 |
By extracting the conditional mode for the random effects, we can
also examine how thermal limits vary across sites beyond the influence
of collection temperatures and body sizes. Shown below are these values,
extracted from the linear mixed effects model. We can see that, similar
to what’s been observed in common garden experiments with A.
tonsa previously, significant divergences are present at only a few
sites, with Fort Hamer and Ritchie Wharf having increased and decreased
thermal limits respectively. Interestingly, both of these sites were low
salinity sites, also in line with previous results suggesting gene flow
between high salinity sites may constrain differentiation.
pop_effs = REsim(ctmax.model) %>%
dplyr::select("site" = groupID, term, mean, sd) %>%
filter(term == "(Intercept)") %>%
inner_join(site_data, by = c("site")) %>%
mutate(site = fct_reorder(site, lat))
#plotREsim(REsim(ctmax.model)) # plot the interval estimates
ggplot(pop_effs, aes(x = lat, y = mean, colour = site)) +
geom_hline(yintercept = 0) +
geom_errorbar(aes(ymin = mean - 1.96 * sd, ymax = mean + 1.96 * sd),
width = 0.5, linewidth = 1) +
geom_point(size = 3) +
scale_colour_manual(values = site_cols) +
labs(x = "Latitude",
y = "Population Effect") +
theme_matt() +
theme(legend.position = "right")

Finally, shown below are the estimated random slopes for each site.
These represent the effects of collection temperature on CTmax for each
site. Interestingly, these estimates diverge from the results of
previous common garden experiments, which showed the strongest
plasticity in high latitude sites. Here, acclimation appears to peak in
mid-latitudes, and decrease at both high and low latitude sites.
coefficients(ctmax.model)$site %>%
janitor::clean_names() %>%
rownames_to_column(var = "site") %>%
inner_join(site_data) %>%
mutate(site = fct_reorder(site, lat)) %>%
ggplot(aes(x = temp_cent, y = site)) +
geom_point(aes(colour = site),
size = 5) +
scale_colour_manual(values = site_cols) +
labs(x = "ARR") +
theme_matt() +
theme(legend.position = "none",
axis.title.y = element_blank())

Trait Variability
Shown below is the trait variation (ranges) for each site. Ranges are
calculated for each collection separately.
trait_ranges = full_data %>%
group_by(site, season, collection_temp, collection_salinity, doy, lat) %>%
summarise(mean_ctmax = mean(ctmax),
ctmax_range = max(ctmax) - min(ctmax),
ctmax_var = var(ctmax),
mean_size = mean(size),
size_range = max(size) - min(size),
size_var = var(size)) %>%
mutate(prop_ctmax_range = ctmax_range / mean_ctmax,
prop_size_range = size_range / mean_size)
ctmax_range_temp = ggplot(trait_ranges, aes(x = collection_temp, y = ctmax_range, colour = site)) +
geom_point(size = 3) +
scale_colour_manual(values = site_cols) +
labs(y = "CTmax Range (°C)",
x = "Collection Temp. (°C)") +
theme_matt() +
theme(legend.position = "right")
ctmax_var_temp = ggplot(trait_ranges, aes(x = collection_temp, y = ctmax_var, colour = site)) +
geom_point(size = 3) +
scale_colour_manual(values = site_cols) +
labs(y = "CTmax Range (°C)",
x = "Collection Temp. (°C)") +
theme_matt() +
theme(legend.position = "right")
size_range_temp = ggplot(trait_ranges, aes(x = collection_temp, y = size_range, colour = site)) +
geom_point(size = 3) +
scale_colour_manual(values = site_cols) +
labs(y = "Size Range (mm)",
x = "Collection Temp. (°C)") +
theme_matt() +
theme(legend.position = "right")
size_var_temp = ggplot(trait_ranges, aes(x = collection_temp, y = size_var, colour = site)) +
geom_point(size = 3) +
scale_colour_manual(values = site_cols) +
labs(y = "Size Range (mm)",
x = "Collection Temp. (°C)") +
theme_matt() +
theme(legend.position = "right")
ggarrange(ctmax_range_temp, size_range_temp, common.legend = T, legend = "right")

Changes in trait variance may be indicative of phenotypic selection.
If selection (as opposed to acclimation) are driving seasonal changes,
we may expect to see a reduction in variance in the peak samples
relative to the early season samples. Note that early season collection
temperatures this year were higher than expected, driven by fairly
strong heatwaves across the North Atlantic. As shown in the temperature
profiles for each site, the ‘early’ samples were collected just after
high temperatures were reached, while ‘peak’ samples were collected
after sites had experienced high temperatures for several weeks
(generations). As warming tolerances were fairly high throughout this
period, we will assume that selection was weak before the early samples.
If the early onset of high temperatures filtered out vulnerable
genotypes prior to our sampling, the results will be a conservative
estimate of the effects of selection on trait variance.
Shown below is the seasonal progression of variance in CTmax for each
site. For many sites, variance decreased between the early and peak
samples, and then increased again in the late sample. For some sites
(e.g. Esker Point), this increase in the late sample was
substantial.
ggplot(trait_ranges, aes(x = season, y = ctmax_var, colour = site)) +
geom_line(aes(group = site),
linewidth = 1.5) +
geom_point(size = 3) +
scale_colour_manual(values = site_cols) +
labs(y = "CTmax Variance",
x = "Season") +
theme_matt() +
theme(legend.position = "right",
legend.title.align = 0.125)

Shown below is the seasonal progression of variance in body size. A
similar pattern of decreasing variance in peak samples relative to early
and late samples is again seen for many sites. The obvious exception is
the Esker Point sample, which saw the opposite trend.
ggplot(trait_ranges, aes(x = season, y = size_var, colour = site)) +
geom_line(aes(group = site),
linewidth = 1.5) +
geom_point(size = 3) +
scale_colour_manual(values = site_cols) +
labs(y = "CTmax Variance",
x = "Season") +
theme_matt() +
theme(legend.position = "right",
legend.title.align = 0.125)

Shown below are the seasonal changes in trait variance for each site
individually.
ggplot(trait_ranges, aes(x = season, y = ctmax_var, colour = site)) +
facet_wrap(site~.) +
geom_line(aes(group = site),
linewidth = 1.5) +
geom_point(size = 3) +
scale_colour_manual(values = site_cols) +
labs(y = "CTmax Variance",
x = "Season") +
theme_matt() +
theme(legend.position = "none",
legend.title.align = 0.125)

ggplot(trait_ranges, aes(x = season, y = size_var, colour = site)) +
facet_wrap(site~.) +
geom_line(aes(group = site),
linewidth = 1.5) +
geom_point(size = 3) +
scale_colour_manual(values = site_cols) +
labs(y = "CTmax Variance",
x = "Season") +
theme_matt() +
theme(legend.position = "none",
legend.title.align = 0.125)

Comparing rates of change
Both CTmax and body size varied between sites and across seasons. It
can be difficult to directly compare these two traits. We take two
approaches to ease this comparison. Shown below is a comparison of the
slopes from the trait regressions against collection temperature for
each population, standardized by the standard deviation of the trait for
each population (across all collections). This presents change per
degree change in collection temperature in units of standard deviations
for both CTmax and body size.
adj_slopes = full_data %>%
group_by(site, lat) %>%
arrange(doy) %>%
filter(site != "Key Largo") %>%
summarize("ctmax_slope" = coef(lm(ctmax ~ collection_temp))["collection_temp"],
"mean_ctmax" = mean(ctmax),
"ctmax_sd" = sd(ctmax),
"size_slope" = coef(lm(size ~ collection_temp))["collection_temp"],
"mean_size" = mean(size),
"size_sd" = sd(size),
"temp_range" = max(collection_temp) - min(collection_temp)) %>%
drop_na() %>%
mutate(adj_ctmax_slope = ctmax_slope / ctmax_sd,
adj_size_slope = size_slope / size_sd) %>%
pivot_longer(cols = contains("_slope"),
names_to = "slope_type",
values_to = "slope")
# ggplot(adj_slopes, aes(x = lat, y = temp_range)) +
# geom_point() +
# theme_matt()
ggplot(filter(adj_slopes, str_detect(slope_type, "adj_")), aes(x = slope_type, y = abs(slope),
group = site, colour = site)) +
geom_hline(yintercept = 0) +
geom_line(linewidth = 1) +
scale_colour_manual(values = site_cols) +
labs(x = "",
y = "Slope (absolute value)") +
theme_matt() +
theme(legend.position = "right",
axis.text.x = element_text(angle = 300, hjust = 0, vjust = 0.5))

Haldanes are a similar unit, representing change in units of standard
deviations per generation. This can be a useful metric for comparing
across traits, especially as the number of generations covered by our
sampling period likely varies across populations. The calculation of
haldanes is taken from Hendry and Kinnison (1999), which in turn is
based on work from Gingerich (1993). We estimated the number of
generations passed between collections using the empirical relationship
between temperature and development time for Acartia tonsa from
Leandro et al. (2006). For initial estimates, we used a temperature
halfway between what was observed during collection, although this
estimate can be improved by using non-linear averaging to account for
Jenzen’s Inequality and the effect of temperature variation on rate
functions. Changes were examined for each pair of collections (early to
peak, and peak to late).
Shown below is a comparison of the estimated haldane values for CTmax
and body size, separated by season. Keep in mind that while this metric
accounts for differences in the number of generations between
collections, it does not directly account for differences in
temperature, leading to inflated values in the “peak to late”
comparisons, which typically covered a larger range of temperatures.
early_peak = full_data %>%
filter(season %in% c("early", "peak")) %>%
mutate(season = if_else(season == "early", "one", "two")) %>%
group_by(site) %>%
mutate(ctmax_sd_p = sd(ctmax),
size_sd_p = sd(size),
temp_change = max(collection_temp) - min(collection_temp),
avg_temp = (max(collection_temp) + min(collection_temp)) / 2,
days_passed = max(doy) - min(doy)) %>%
select(site, lat, season,
ctmax_sd_p, size_sd_p,
temp_change, avg_temp, days_passed,
ctmax, size) %>%
group_by(site, lat, season,
ctmax_sd_p, size_sd_p,
temp_change, avg_temp, days_passed) %>%
summarize(ctmax = mean(ctmax),
size = mean(size)) %>%
pivot_wider(id_cols = c(site, lat, ctmax_sd_p, size_sd_p,
temp_change, avg_temp, days_passed),
names_from = season,
values_from = c(ctmax, size)) %>%
mutate(season = "early_to_peak") %>%
drop_na()
peak_late = full_data %>%
filter(season %in% c("peak", "late")) %>%
mutate(season = if_else(season == "peak", "one", "two")) %>%
group_by(site) %>%
mutate(ctmax_sd_p = sd(ctmax),
size_sd_p = sd(size),
temp_change = last(collection_temp) - first(collection_temp),
avg_temp = (max(collection_temp) + min(collection_temp)) / 2,
days_passed = max(doy) - min(doy)) %>%
select(site, lat, season, ctmax_sd_p, size_sd_p,
temp_change, avg_temp, days_passed,
ctmax, size) %>%
group_by(site, lat, season, ctmax_sd_p, size_sd_p,
temp_change, avg_temp, days_passed) %>%
summarize(ctmax = mean(ctmax),
size = mean(size)) %>%
pivot_wider(id_cols = c(site, lat, ctmax_sd_p, size_sd_p,
temp_change, avg_temp, days_passed),
names_from = season,
values_from = c(ctmax, size)) %>%
mutate(season = "peak_to_late") %>%
drop_na()
calc_halds = function(x1, x2, sd_p, g){
((x2 / sd_p) - (x1 / sd_p)) / g
}
haldanes = bind_rows(early_peak, peak_late) %>%
mutate("gen_time" = 5490*(avg_temp + 1)^-2.05,
"gens" = floor(days_passed / gen_time),
"ctmax_haldanes" = calc_halds(x2 = ctmax_two, x1 = ctmax_one,
sd_p = ctmax_sd_p, g = gens),
"size_haldanes" = calc_halds(x2 = size_two, x1 = size_one,
sd_p = size_sd_p, g = gens))
# haldanes %>%
# ungroup() %>%
# select(site, temp_change, season, ctmax_haldanes, size_haldanes) %>%
# pivot_longer(cols = c(ctmax_haldanes, size_haldanes),
# names_to = c("type", NA),
# names_sep = "_",
# values_to = "haldanes") %>%
# ggplot(aes(x = type, y = haldanes, group = site, colour = site)) +
# facet_wrap(season~.) +
# geom_hline(yintercept = 0) +
# geom_line(aes(linewidth = desc(temp_change))) +
# scale_colour_manual(values = site_cols) +
# labs(x = "Trait",
# y = "Haldanes",
# linewidth = "Temp. Change") +
# theme_matt_facets()
ctmax_halds_plot = haldanes %>%
ungroup() %>%
select(site, temp_change, season, ctmax_haldanes, size_haldanes) %>%
ggplot(aes(x = season, y = ctmax_haldanes, colour = site, group = site)) +
geom_hline(yintercept = 0, colour = "grey70") +
geom_line(linewidth = 2) +
scale_colour_manual(values = site_cols) +
labs(x = "Season",
y = "Haldanes") +
ggtitle("CTmax") +
theme_matt() +
theme(legend.position = "right")
size_halds_plot = haldanes %>%
ungroup() %>%
select(site, temp_change, season, ctmax_haldanes, size_haldanes) %>%
ggplot(aes(x = season, y = size_haldanes, colour = site, group = site)) +
geom_hline(yintercept = 0, colour = "grey70") +
geom_line(linewidth = 2) +
scale_colour_manual(values = site_cols) +
labs(x = "Season",
y = "Haldanes") +
ggtitle("Size") +
theme_matt() +
theme(legend.position = "right")
ggarrange(ctmax_halds_plot, size_halds_plot, common.legend = T, legend = "bottom")

Why does intraspecific data matter?
Thermal limits vary substantially across both spatial and temporal
scales in this species, highlighting the importance of considering both
intraspecific and temporal variation in thermal limits for predictions
of vulnerability to climate change. Single point estimates of thermal
limits (as commonly used in larger, general analyses across taxa)
obscure this crucial variation, and may bias our estimates of spatial
patterns in vulnerability. Here we explore three separate scenarios to
illustrate and quantify the importance of this intraspecific
vulnerability.
Scenario 1 - Invariant thermal limits
The first scenario assumes that thermal limits are constant across
both spatial and temporal axes (i.e. a single point estimate of the
thermal limit for this species). Here we selected a central population
(the high salinity Chesapeake Bay site), and used the average thermal
limit from the peak season sample as our ‘representative’ thermal limit.
This approach is similar to that used in Bennet et al. to compile the
GlobTherm dataset. These thermal limits are used to re-estimate warming
tolerance for each collection (mean thermal limit - collection
temperature). We then compared this predicted warming tolerance with the
actual observed warming tolerances from each collection. A positive
difference indicates an overestimated warming tolerance (the population
is actually closer to their thermal limits than would be predicted from
the estimated value, and therefore more vulnerable). A negative
difference indicates an underestimated warming tolerance (the population
is further from their thermal limit than would be predicted, and
therefore less vulnerable).
Both overestimates and underestimates can be problematic for accurate
management and conservation strategies. We summarize each of the
scenarios using 1) the number of populations with a difference between
estimates >2°C in either direction, 2) the average magnitude of
difference for that subset of populations, and 3) the slope of the
difference against latitude. Effective estimation strategies will have a
small number of populations with under- or over-estimated warming
tolerance, a small magnitude difference between predicted and observed
warming tolerance, and a shallow latitudinal slope.
In this first scenario (single point estimate of thermal limits), the
effectiveness of the estimate varied across latitude and across seasons.
During the early season, thermal limits from the central site were a
decent predictor of warming tolerance at the other sites, and there was
only a slight latitudinal trend. This latitudinal trend increased,
however, during the peak and late season collections, driven by
increasingly large differences in the northern sites (indicating
increased vulnerability relative to predictions in these sites). During
the peak season collection, warming tolerance in the southern sites was
underestimated by several degrees (these populations were less
vulnerable than predicted by the central site thermal limits).
# Compare estimated warming tolerance "ranges" when: 1) CTmax for "average" collection is used; 2) When CTmax for one collection per population is used; and 3) When all collections are used. The idea is to show that not accounting for intra-specific and intra-population variation leads to incorrect predictions of vulnerability to warming because this variation can be substantial - across populations within each seasonal collection, there is at least 5°C variation in thermal limits, while across collections within populations, acclimation to changes in temperature can drive substantial variation.
## Scenario 1 - single point estimates
est_1 = full_data %>%
group_by(site, season) %>%
summarise("mean_ctmax" = mean(ctmax)) %>%
filter(site == "Tyler Cove", season == "peak")
scenario_1 = full_data %>%
mutate(rep_ctmax = est_1$mean_ctmax,
pred_wt = rep_ctmax - collection_temp,
wt_diff = pred_wt - warming_tol)
ggplot(scenario_1, aes(x = lat, y = wt_diff)) +
facet_wrap(season~., nrow = 3) +
geom_hline(yintercept = 0) +
geom_smooth(method = "lm") +
geom_point() +
labs(x = "Latitude",
y = "Predicted - Observed WT") +
theme_matt_facets()

lat.model1 = lm(data = scenario_1,
wt_diff ~ lat*season)
lat_slope_1 = emmeans::emtrends(lat.model1, var = "lat", specs = "season") %>%
as.data.frame() %>%
select(season, lat.trend)
performance_1 = scenario_1 %>%
select(site, lat, season, wt_diff) %>%
group_by(site, season, lat) %>%
summarise("mean_diff" = mean(wt_diff),
"abs_diff" = abs(mean_diff)) %>%
ungroup() %>%
mutate("flag" = if_else(abs_diff >= 2, "yes", "no")) %>%
filter(flag == "yes") %>%
group_by(season) %>%
summarise("avg_diff" = mean(abs_diff),
"n" = n()) %>%
inner_join(lat_slope_1, by = "season")
Scenario 2 - Seasonally invariant thermal limits
Local adaptation of thermal limits is widely observed across a range
of taxa, including Acartia tonsa. In the second scenario, we
account for this by using average thermal limits from the peak season
for each population in the estimates of warming tolerance throughout the
year.
Unsurprisingly, this approach eliminates the latitudinal trend.
Instead we see that peak season estimates were generally decent
predictors of warming tolerance during the early season (although there
were slight overestimates in several populations), and slightly
underestimated warming tolerance during the late season.
est_2 = full_data %>%
group_by(site, season) %>%
summarise("mean_ctmax" = mean(ctmax)) %>%
filter(season == "peak") %>%
select(site, mean_ctmax)
scenario_2 = full_data %>%
inner_join(est_2, by = c("site")) %>%
mutate(pred_wt = mean_ctmax - collection_temp,
wt_diff = pred_wt - warming_tol)
ggplot(scenario_2, aes(x = lat, y = wt_diff)) +
facet_wrap(season~., nrow = 3) +
geom_hline(yintercept = 0) +
geom_smooth(method = "lm") +
geom_point() +
labs(x = "Latitude",
y = "Predicted - Observed WT") +
theme_matt_facets()

lat.model2 = lm(data = scenario_2,
wt_diff ~ lat*season)
lat_slope_2 = emmeans::emtrends(lat.model2, var = "lat", specs = "season") %>%
as.data.frame() %>%
select(season, lat.trend)
performance_2 = scenario_2 %>%
select(site, lat, season, wt_diff) %>%
group_by(site, season, lat) %>%
summarise("mean_diff" = mean(wt_diff),
"abs_diff" = abs(mean_diff)) %>%
ungroup() %>%
mutate("flag" = if_else(abs_diff >= 2, "yes", "no")) %>%
filter(flag == "yes") %>%
group_by(season) %>%
summarise("avg_diff" = mean(abs_diff),
"n" = n()) %>%
inner_join(lat_slope_2, by = c("season"))
Scenario 3 - Population sub-sampling
Both of the previous approaches to estimating warming tolerance
result in overestimates of warming tolerance. These reductive methods
increase the feasibility, but are unable to account for the co-occuring
shifts in ambient temperature and thermal limits. Continuous in-situ
monitoring of thermal limits is impractical, however, especially for
species with small popuation sizes and/or very large range
distributions. One potential compromise solution is to sub-sample
populations and use observed data to predict spatial and seasonal
changes in warming tolerance.
In this third approach, we randomly selected nine collections, fit a
linear model of CTmax ~ collection temperature, and used this regression
to predict thermal limits and warming tolerance across the full set of
collections. These predicted warming tolerance values were then compared
against observed warming tolerance as before. We repeated this process
100 times (100 random sets of 9 collections) to examine the sensitivity
of this approach the populations and seasons collected. In addition to
this random data, we also included a scenario where all seasonal
collections from Ft. Hamer, Tyler Cove, and Miramichi (the latitudinal
extremes and a central point) were used to predict thermal limits.
scenario_3 = data.frame()
performance_3 = data.frame()
for(i in 1:100){
est_3 = full_data %>%
group_by(site, season, collection_temp) %>%
summarise("mean_ctmax" = mean(ctmax), .groups = "keep") %>%
ungroup() %>%
filter(row_number() %in% sample(c(1:max(row_number())), size = 9, replace = F))
rep.model = lm(data = est_3, mean_ctmax ~ collection_temp)
rep_data = full_data %>%
group_by(site, season) %>%
mutate(mean_wt = mean(warming_tol)) %>%
select(site, season, collection_temp, lat, mean_wt) %>%
ungroup() %>%
distinct() %>%
mutate(pred_ctmax = predict(rep.model, newdata = .),
pred_wt = pred_ctmax - collection_temp,
wt_diff = pred_wt - mean_wt,
run = i,
group = "random")
scenario_3 = bind_rows(scenario_3, rep_data)
lat.model3 = lm(data = scenario_3,
wt_diff ~ lat*season)
lat_slope_3 = emmeans::emtrends(lat.model3, var = "lat", specs = "season") %>%
as.data.frame() %>%
select(season, lat.trend)
rep_performance = scenario_3 %>%
select(site, lat, season, wt_diff) %>%
group_by(site, season, lat) %>%
summarise("mean_diff" = mean(wt_diff),
"abs_diff" = abs(mean_diff),
.groups = "keep") %>%
ungroup() %>%
mutate("flag" = if_else(abs_diff >= 2, "yes", "no")) %>%
filter(flag == "yes") %>%
group_by(season) %>%
summarise("avg_diff" = mean(abs_diff),
"n" = n(),
.groups = "keep") %>%
inner_join(lat_slope_3, by = c("season"))
performance_3 = bind_rows(performance_3, rep_performance)
}
gold_stand = full_data %>%
group_by(site, season, collection_temp) %>%
summarise("mean_ctmax" = mean(ctmax), .groups = "keep") %>%
ungroup() %>%
filter(site %in% c("Ft. Hamer", "Tyler Cove", "Miramichi"))
gold.model = lm(data = gold_stand, mean_ctmax ~ collection_temp)
gold_data = full_data %>%
group_by(site, season) %>%
mutate(mean_wt = mean(warming_tol)) %>%
select(site, season, collection_temp, lat, mean_wt) %>%
ungroup() %>%
distinct() %>%
mutate(pred_ctmax = predict(gold.model, newdata = .),
pred_wt = pred_ctmax - collection_temp,
wt_diff = pred_wt - mean_wt,
run = i + 1,
group = "gold")
gold.model = lm(data = gold_data,
wt_diff ~ lat*season)
gold_slope = emmeans::emtrends(gold.model, var = "lat", specs = "season") %>%
as.data.frame() %>%
select(season, lat.trend)
gold_performance = gold_data %>%
select(site, lat, season, wt_diff) %>%
group_by(site, season, lat) %>%
summarise("mean_diff" = mean(wt_diff),
"abs_diff" = abs(mean_diff),
.groups = "keep") %>%
ungroup() %>%
mutate("flag" = if_else(abs_diff >= 2, "yes", "no")) %>%
filter(flag == "yes") %>%
group_by(season) %>%
summarise("avg_diff" = mean(abs_diff),
"n" = n(),
.groups = "keep") %>%
inner_join(gold_slope, by = c("season"))
scenario_3 = bind_rows(scenario_3, gold_data)
performance_3_sum = performance_3 %>%
group_by(season) %>%
summarise("avg_diff" = mean(avg_diff),
"n" = mean(n),
"lat.trend" = mean(lat.trend))
ggplot(scenario_3, aes(x = lat, y = wt_diff, colour = group, group = run)) +
facet_wrap(season~., nrow = 3) +
geom_hline(yintercept = 0) +
geom_smooth(aes(colour = group),
method = "lm", se = F) +
geom_point() +
labs(x = "Latitude",
y = "Predicted - Observed WT") +
theme_matt_facets()

knitr::kable(performance_1, caption = "Scenario 1")
Scenario 1
| early |
2.879537 |
1 |
0.0942793 |
| peak |
3.059815 |
3 |
0.2746916 |
| late |
4.059209 |
6 |
0.2516853 |
knitr::kable(performance_2, caption = "Scenario 2")
Scenario 2
| early |
2.208815 |
1 |
-0.1249784 |
| late |
2.692996 |
5 |
-0.0248105 |
knitr::kable(performance_3_sum, caption = "Scenario 3")
Scenario 3
| peak |
3.713519 |
1.00 |
0.0954369 |
| late |
2.155182 |
1.88 |
0.1651261 |
knitr::kable(gold_performance, caption = "`Gold` Standard")
Gold Standard
| early |
2.795142 |
1 |
0.0766049 |
| peak |
4.837180 |
1 |
0.1476920 |
| late |
3.116444 |
3 |
0.1901852 |
best = bind_rows(
mutate(performance_1, "scenario" = "one"),
mutate(performance_2, "scenario" = "two"),
mutate(performance_3_sum, "scenario" = "three"),
mutate(gold_performance, "scenario" = "gold")) %>%
group_by(season) %>%
filter(abs(lat.trend) == min(abs(lat.trend)))
#filter(avg_diff == min(avg_diff))
Next Steps
After phenotyping, each individual was preserved in 95% ethanol.
Individual DNA libraries will be prepared using Twist Bio 96-plex prep
kits, then sequenced on an Illumina NovaSeq X Plus. Using the
low-coverage whole genome sequences, we will examine seasonal patterns
in allele frequency change, and compare these fine scale temporal
patterns with the larger latitudinal patterns in allele frequency to
determine whether the same alleles driving rapid seasonal adaptation are
in play over larger spatial (and longer temporal) scales.
Misc. Details
ggplot(temp_record, aes(x = minute_passed, y = temp_C, group = factor(run))) +
geom_abline(slope = 0.3, intercept = mean(temp_record[temp_record$minute_interval == 0, 8])) +
geom_abline(slope = 0.1, intercept = mean(temp_record[temp_record$minute_interval == 0, 8])) +
geom_line(linewidth = 0.2, alpha = 0.8) +
geom_point(data = full_data,
aes(x = time, y = ctmax + 0.4),
size = 2,
shape = 25) +
labs(x = "Time passed (minutes)",
y = "Temperature (degrees C)",
fill = "Trial Number") +
guides(colour = "none") +
theme_matt(base_size = 16) +
theme(legend.position = "right")

ramp_record2 = ramp_record %>%
group_by(run, minute_interval) %>%
summarise(mean_ramp = mean(ramp_per_minute)) %>%
ungroup()
ggplot(ramp_record2, aes(x = minute_interval, y = mean_ramp)) +
geom_hline(yintercept = 0.3) +
geom_hline(yintercept = 0.1) +
#geom_point() +
geom_hex(bins = 30) +
ylim(0, 0.35) +
labs(y = "Ramp Rate (deg. C / min.)",
x = "Time into run (minute)") +
theme_matt(base_size = 16)

full_data %>%
drop_na(replicate) %>%
ggplot(aes(x = factor(replicate), y = ctmax, group = site)) +
facet_grid(site~season, scales = "free_y") +
geom_point(position = position_jitter(width = 0.1, height = 0),
alpha = 0.4,
colour = "grey30") +
geom_smooth(method = "lm", colour = "black") +
labs(x = "Replicate",
y = "CTmax") +
theme_matt_facets()

ggplot(haldanes, aes(x = lat, y = gens, colour = site, shape = season)) +
geom_hline(yintercept = 0) +
geom_point(size = 5) +
scale_colour_manual(values = site_cols) +
labs(x = "Latitude",
y = "Generations between \ncollections") +
scale_y_continuous(breaks = seq(from = 0, to = 21, by = 5)) +
theme_matt() +
theme(legend.position = "right")

obs_ranks = ggplot(full_data, aes(x = rank)) +
facet_wrap(tube~.) +
geom_histogram(binwidth = 1) +
scale_x_continuous(breaks = c(2,4,6,8,10)) +
ggtitle("Observation") +
theme_matt_facets()
sim_data = data.frame()
for(i in 1:max(full_data$run)){
rep_data = data.frame("tube" = sample(c(1:10), size = 10, replace = F),
"rank" = c(1:10),
"rep" = i) %>%
arrange(tube)
sim_data = bind_rows(sim_data, rep_data)
}
sim_ranks = ggplot(sim_data, aes(x = rank)) +
facet_wrap(tube~.) +
geom_histogram(binwidth = 1) +
scale_x_continuous(breaks = c(2,4,6,8,10)) +
ggtitle("Simulation") +
theme_matt_facets()
ggarrange(obs_ranks, sim_ranks)

LS0tCnRpdGxlOiAiQ29tcGFyaW5nIHNlYXNvbmFsIGFuZCBsYXRpdHVkaW5hbCBwYXR0ZXJucyBpbiB0aGVybWFsIGFkYXB0YXRpb24iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgICAgICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICAgICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICAgICAgICB0b2M6IHRydWUKICAgICAgICAgIHRvY19mbG9hdDogdHJ1ZQogIGdpdGh1Yl9kb2N1bWVudDoKICAgICAgICAgIGh0bWxfcHJldmlldzogZmFsc2UKICAgICAgICAgIHRvYzogdHJ1ZQogICAgICAgICAgdG9jX2RlcHRoOiAzCi0tLQoKYGBge3J9CiMgVE8gRE8gCiMgLSBGcmFtZXdvcmsgZm9yIHF1YW50aWZ5aW5nIHRoZSBlZmZlY3RzIG9mIHdpdGhpbi0gYW5kIGFjcm9zcy1wb3B1bGF0aW9uIHZhcmlhdGlvbiBpbiB0aGVybWFsIGxpbWl0cyB0byBzcGF0aWFsIHBhdHRlcm5zIGluIHZ1bG5lcmFiaWxpdHkgdG8gd2FybWluZy4gQ29tcGFyaW5nIHByZWRpY3Rpb25zIGJhc2VkIG9uIDEpIG1lZGlhbiwgMikgb3ZlcmFsbCBDVG1heCB2cy4gdGVtcCByZWdyZXNzaW9uLCAzKSBwb3B1bGF0aW9uIHZhcmlhdGlvbiBpbiBpbnRlcmNlcHRzLCA0KSBwb3B1bGF0aW9uIHZhcmlhdGlvbiBpbiBib3RoIHNsb3BlIGFuZCBpbnRlcmNlcHQuIFRoZSBlbmQgbWV0cmljIEkgY291bGQgdXNlIHRvIGNvbXBhcmUgYWNyb3NzIHNjZW5hcmlvcyBpcyBpKSB0aGUgY3VtdWxhdGl2ZSBhbW91bnQgb2YgdW5kZXJlc3RpbWF0aW9uIChzdW1tZWQgYWNyb3NzIHBvcHVsYXRpb25zKSBvciBpaSkgdGhlIG51bWJlciBvZiBzaXRlcyB0aGF0IGhhdmUgb3ZlcmVzdGltYXRlZCBXVCwgb3IgaWlpKSB0aGUgc2xvcGUgb2YgV1QgKGxvY2FsIGFkYXB0YXRpb24gYW5kIHNlYXNvbmFsIGFjY2xpbWF0aW9uIHNob3VsZCByZXN1bHQgaW4gbW9yZSBzaGFsbG93IHNsb3BlcykuIApgYGAKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1ULCBtZXNzYWdlID0gRiwgd2FybmluZyA9IEYsIGVjaG8gPSBGfQoKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBrbml0cjo6aXNfaHRtbF9vdXRwdXQoKSwKICBmaWcuYWxpZ24gPSAiY2VudGVyIiwKICBmaWcucGF0aCA9ICIuLi9GaWd1cmVzL21hcmtkb3duLyIsCiAgZGV2ID0gYygicG5nIiwgInBkZiIpLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UsCiAgY29sbGFwc2UgPSBUCikKCnRoZW1lX21hdHQgPSBmdW5jdGlvbihiYXNlX3NpemUgPSAxOCwKICAgICAgICAgICAgICAgICAgICAgIGRhcmtfdGV4dCA9ICJncmV5MjAiKXsKICBtaWRfdGV4dCA8LSAgbW9ub2Nocm9tZVI6OmdlbmVyYXRlX3BhbGV0dGUoZGFya190ZXh0LCAiZ29fbGlnaHRlciIsIG5fY29sb3VycyA9IDUpWzJdCiAgbGlnaHRfdGV4dCA8LSAgbW9ub2Nocm9tZVI6OmdlbmVyYXRlX3BhbGV0dGUoZGFya190ZXh0LCAiZ29fbGlnaHRlciIsIG5fY29sb3VycyA9IDUpWzNdCiAgCiAgdGhlbWVfcHVicihiYXNlX2ZhbWlseT0ic2FucyIpICUrcmVwbGFjZSUgCiAgICB0aGVtZSgKICAgICAgcGFuZWwuYmFja2dyb3VuZCAgPSBlbGVtZW50X3JlY3QoZmlsbD0idHJhbnNwYXJlbnQiLCBjb2xvdXI9TkEpLCAKICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9InRyYW5zcGFyZW50IiwgY29sb3VyPU5BKSwgCiAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9InRyYW5zcGFyZW50IiwgY29sb3VyPU5BKSwKICAgICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChmaWxsPSJ0cmFuc3BhcmVudCIsIGNvbG91cj1OQSksCiAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gbWlkX3RleHQsIGxpbmVoZWlnaHQgPSAxLjEpLAogICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gYmFzZV9zaXplICogMS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBkYXJrX3RleHQpLAogICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGJhc2Vfc2l6ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IG1pZF90ZXh0KSwKICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSBiYXNlX3NpemUgKiAxLjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXJnaW4gPSB1bml0KGMoMywgMCwgMCwgMCksICJtbSIpKSwKICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSBiYXNlX3NpemUgKiAxLjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXJnaW4gPSB1bml0KGMoMCwgNSwgMCwgMCksICJtbSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuZ2xlID0gOTApLAogICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPWJhc2Vfc2l6ZSAqIDAuOSksCiAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gYmFzZV9zaXplICogMC45LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2UgPSAiYm9sZCIpLAogICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigwLjI1LCAwLjI1LCAwLjI1LCAwLjI1LCJjbSIpCiAgICApCn0KCnRoZW1lX21hdHRfZmFjZXRzID0gZnVuY3Rpb24oYmFzZV9zaXplID0gMTgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGFya190ZXh0ID0gImdyZXkyMCIpewogIG1pZF90ZXh0IDwtICBtb25vY2hyb21lUjo6Z2VuZXJhdGVfcGFsZXR0ZShkYXJrX3RleHQsICJnb19saWdodGVyIiwgbl9jb2xvdXJzID0gNSlbMl0KICBsaWdodF90ZXh0IDwtICBtb25vY2hyb21lUjo6Z2VuZXJhdGVfcGFsZXR0ZShkYXJrX3RleHQsICJnb19saWdodGVyIiwgbl9jb2xvdXJzID0gNSlbM10KICAKICB0aGVtZV9idyhiYXNlX2ZhbWlseT0ic2FucyIpICUrcmVwbGFjZSUgCiAgICB0aGVtZSgKICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGFuZWwuYmFja2dyb3VuZCAgPSBlbGVtZW50X3JlY3QoZmlsbD0idHJhbnNwYXJlbnQiLCBjb2xvdXI9TkEpLCAKICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9InRyYW5zcGFyZW50IiwgY29sb3VyPU5BKSwgCiAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9InRyYW5zcGFyZW50IiwgY29sb3VyPU5BKSwKICAgICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChmaWxsPSJ0cmFuc3BhcmVudCIsIGNvbG91cj1OQSksCiAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gbWlkX3RleHQsIGxpbmVoZWlnaHQgPSAxLjEpLAogICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IGJhc2Vfc2l6ZSksCiAgICAgIHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSBiYXNlX3NpemUgKiAxLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGRhcmtfdGV4dCksCiAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gYmFzZV9zaXplLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gbWlkX3RleHQpLAogICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IGJhc2Vfc2l6ZSAqIDEuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcmdpbiA9IHVuaXQoYygzLCAwLCAwLCAwKSwgIm1tIikpLAogICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGJhc2Vfc2l6ZSAqIDEuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcmdpbiA9IHVuaXQoYygwLCA1LCAwLCAwKSwgIm1tIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5nbGUgPSA5MCksCiAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9YmFzZV9zaXplICogMC45KSwKICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSBiYXNlX3NpemUgKiAwLjksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiksCiAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAuMjUsIDAuMjUsIDAuMjUsIDAuMjUsImNtIikKICAgICkKfQoKc2l0ZV9jb2xzID0gYygiS2V5IExhcmdvIiA9ICJpbmRpYW5yZWQ0IiwgCiAgICAgICAgICAgICAgIk1hbmF0ZWUgUml2ZXIiID0gImNvcmFsIiwgCiAgICAgICAgICAgICAgIkZ0LiBIYW1lciIgPSAiY29yYWwzIiwKICAgICAgICAgICAgICAiVHlsZXIgQ292ZSIgPSAiZ29sZGVucm9kMSIsCiAgICAgICAgICAgICAgIkdhbmV5J3MgV2hhcmYiID0gImRhcmtnb2xkZW5yb2QzIiwgCiAgICAgICAgICAgICAgIkVza2VyIFBvaW50IiA9ICJkYXJrc2VhZ3JlZW4zIiwKICAgICAgICAgICAgICAiU2F3eWVyIFBhcmsiID0gInBhbGVncmVlbjQiLCAKICAgICAgICAgICAgICAiU3QuIFRob21hcyBkZSBLZW50IFdoYXJmIiA9ICJzdGVlbGJsdWUyIiwKICAgICAgICAgICAgICAiUml0Y2hpZSBXaGFyZiIgPSAic3RlZWxibHVlNCIpCmBgYAoKIyMgU2l0ZSBDaGFyYWN0ZXJpc3RpY3MKCmBgYHtyfQpzaXRlX3RlbXBzID0gZnVsbF9kYXRhICU+JSAKICBkcGx5cjo6c2VsZWN0KHNpdGUsIGxhdCwgc2Vhc29uLCBkb3ksIGNvbGxlY3Rpb25fdGVtcCwgY29sbGVjdGlvbl9zYWxpbml0eSkgJT4lICAKICBkaXN0aW5jdCgpICU+JSAKICBmaWx0ZXIoZG95ID4gMTAwKSAKYGBgCgpDb3BlcG9kcyB3ZXJlIGNvbGxlY3RlZCBieSBzdXJmYWNlIHRvdyBmcm9tIHNpdGVzIGFjcm9zcyB0aGUgV2VzdGVybiBBdGxhbnRpYyBhdCBzZXZlcmFsIHRpbWVzIHRocm91Z2hvdXQgdGhlIHllYXIuIFRoZSBzaXRlcyBhcmUgc2hvd24gYmVsb3cuIFRlbXBlcmF0dXJlcyBhdCB0aGUgdGltZSBvZiBjb2xsZWN0aW9uIHdlcmUgbWVhc3VyZWQgdXNpbmcgYSBtYW51YWwgdGhlcm1vbWV0ZXIuIEFjcm9zcyB0aGUgZW50aXJlIHNldCBvZiBjb2xsZWN0aW9ucywgdGVtcGVyYXR1cmUgcmFuZ2VkIGZyb20gYHIgbWluKHNpdGVfdGVtcHMkY29sbGVjdGlvbl90ZW1wKWDCsEMgdG8gYHIgbWF4KHNpdGVfdGVtcHMkY29sbGVjdGlvbl90ZW1wKWDCsEMuCgpgYGB7ciBzaXRlLWNoYXJzLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9Nn0KY29vcmRzID0gc2l0ZV9kYXRhICU+JQogIGRwbHlyOjpzZWxlY3Qoc2l0ZSwgbG9uZywgbGF0KSAlPiUKICBkaXN0aW5jdCgpCgpzaXRlX21hcCA9IG1hcF9kYXRhKCJ3b3JsZCIpICU+JSAKICBmaWx0ZXIocmVnaW9uICVpbiUgYygiVVNBIiwgIkNhbmFkYSIpKSAlPiUgCiAgZ2dwbG90KCkgKyAKICBnZW9tX3BvbHlnb24oYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSwKICAgICAgICAgICAgICAgZmlsbCA9ICJsaWdodGdyZXkiKSArIAogIGNvb3JkX21hcCh4bGltID0gYygtODUsLTYwKSwKICAgICAgICAgICAgeWxpbSA9IGMoMjUsIDQ4KSkgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBjb29yZHMsCiAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBsb25nLCB5ID0gbGF0LCBjb2xvdXIgPSBzaXRlKSwKICAgICAgICAgICAgIHNpemUgPSAzKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiAgbGFicyh4ID0gIkxvbmdpdHVkZSIsIAogICAgICAgeSA9ICJMYXRpdHVkZSIpICsgCiAgdGhlbWVfbWF0dChiYXNlX3NpemUgPSAxNikKCnNpdGVfdGVtcF9wbG90ID0gZ2dwbG90KHNpdGVfdGVtcHMsIGFlcyh4ID0gZG95LCB5ID0gY29sbGVjdGlvbl90ZW1wLCBjb2xvdXIgPSBzaXRlKSkgKyAKICBnZW9tX2xpbmUobGluZXdpZHRoID0gMikgKyAKICBnZW9tX3BvaW50KHNpemUgPSA1KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiAgbGFicyh5ID0gIlRlbXBlcmF0dXJlICjCsEMpIiwKICAgICAgIHggPSAiRGF5IG9mIHRoZSBZZWFyIikgKwogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCgpnZ2FycmFuZ2Uoc2l0ZV9tYXAsIHNpdGVfdGVtcF9wbG90LCBjb21tb24ubGVnZW5kID0gVCwgbGVnZW5kID0gImJvdHRvbSIpCmBgYAoKQ29sbGVjdGlvbnMgYWltZWQgdG8gb2J0YWluIGNvcGVwb2RzIG5lYXIgdGhlIG9uc2V0IG9mIHBlYWsgdGVtcGVyYXR1cmVzLCBhZnRlciBwZWFrIHRlbXBlcmF0dXJlcywgYW5kIHRoZW4gYXQgbG93IHRlbXBlcmF0dXJlcy4gUmVnaW9uYWwgZGF0YSBpcyBub3QgYXZhaWxhYmxlIGZvciBhbGwgc2l0ZXMsIHNvIGhlcmUgd2UndmUgcGllY2VkIHRvZ2V0aGVyIGRhaWx5IHRlbXBlcmF0dXJlIHZhbHVlcyBmcm9tIGVpdGhlciBsb2NhbCB0ZW1wZXJhdHVyZSBzZW5zb3JzIChzaXRlcyBpbiBGbG9yaWRhIGFuZCB0aGUgQ2hlc2FwZWFrZSkgYW5kIGhpZ2ggcmVzb2x1dGlvbiBzYXRlbGxpdGUgdGVtcGVyYXR1cmUgZGF0YSAoQ29ubmVjdGljdXQsIE1haW5lLCBhbmQgdGhlIENhbmFkaWFuIHNpdGVzKS4gVGhpcyBzYXRlbGxpdGUgZGF0YSBjb21lcyBmcm9tIHRoZSBOT0FBIDEvNMKwIERhaWx5IE9wdGltdW0gSW50ZXJwb2xhdGlvbiBTZWEgU3VyZmFjZSBUZW1wZXJhdHVyZSAoT0lTU1QpLiAKClRoZXNlIHRlbXBlcmF0dXJlIHByb2ZpbGVzIGFyZSBzaG93biBiZWxvdywgd2l0aCB0aGUgdGVtcGVyYXR1cmVzIG1lYXN1cmVkIGR1cmluZyB0aGUgdGltZSBvZiBjb2xsZWN0aW9uIGluY2x1ZGVkIGZvciBjb21wYXJpc29uIEluIHNldmVyYWwgY2FzZXMgY29sbGVjdGlvbiB0ZW1wZXJhdHVyZSBkb2VzIG5vdCBtYXRjaCB0aGUgcmVjb3JkZWQgZGFpbHkgYXZlcmFnZXMsIGJ1dCB0aGUgdGVtcGVyYXR1cmUgcmVjb3JkcyBkbyBnaXZlIGEgZ2VuZXJhbCBzZW5zZSBvZiB0aGUgdGltaW5nIG9mIHNlYXNvbmFsIG1heGltYS4gSW4gZ2VuZXJhbCwgdGhlIGZpcnN0IHNhbXBsZSBmcm9tIGVhY2ggc2l0ZSBmZWxsIGp1c3QgYWZ0ZXIgdGhlIHNpdGUgcmVhY2hlZCB0aGUgd2FybWVzdCBwZXJpb2QuIFRoZSBleGNlcHRpb24gdG8gdGhhdCBwYXR0ZXJuIGlzIGluIEZsb3JpZGEsIHdoZXJlIGNvbGxlY3Rpb25zIG9jY3VycmVkIGFmdGVyIGFuIGV4dGVuZGVkIHBlcmlvZCBvZiBoaWdoIHRlbXBlcmF0dXJlcy4gCgpgYGB7ciBjb250aW51b3VzLXRlbXBzLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQp0ZW1wX3Byb2ZpbGVzID0gdGVtcF9wcm9maWxlcyAlPiUgCiAgbXV0YXRlKHJlZ2lvbiA9IGZjdF9yZWxldmVsKHJlZ2lvbiwgIkZsb3JpZGEiLCAiQ2hlc2FwZWFrZSIsICJDb25uZWN0aWN1dCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNYWluZSIsICJTaGVkaWFjIiwgIk1pcmFtaWNoaSIpKQoKc2l0ZV90ZW1wczIgPSBzaXRlX3RlbXBzICU+JSAKICBtdXRhdGUocmVnaW9uID0gY2FzZV93aGVuKAogICAgc2l0ZSA9PSAiTWFuYXRlZSBSaXZlciIgfiAiRmxvcmlkYSIsCiAgICBzaXRlID09ICJGdC4gSGFtZXIiIH4gIkZsb3JpZGEiLAogICAgc2l0ZSA9PSAiVHlsZXIgQ292ZSIgfiAiQ2hlc2FwZWFrZSIsCiAgICBzaXRlID09ICJHYW5leSdzIFdoYXJmIiB+ICJDaGVzYXBlYWtlIiwKICAgIHNpdGUgPT0gIkVza2VyIFBvaW50IiB+ICJDb25uZWN0aWN1dCIsCiAgICBzaXRlID09ICJTYXd5ZXIgUGFyayIgfiAiTWFpbmUiLAogICAgc2l0ZSA9PSAiU3QuIFRob21hcyBkZSBLZW50IFdoYXJmIiB+ICJTaGVkaWFjIiwKICAgIHNpdGUgPT0gIlJpdGNoaWUgV2hhcmYiIH4gIk1pcmFtaWNoaSIpLAogICAgcmVnaW9uID0gZmN0X3JlbGV2ZWwocmVnaW9uLCAiRmxvcmlkYSIsICJDaGVzYXBlYWtlIiwgIkNvbm5lY3RpY3V0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICJNYWluZSIsICJTaGVkaWFjIiwgIk1pcmFtaWNoaSIpKQoKZ2dwbG90KHRlbXBfcHJvZmlsZXMsIGFlcyh4ID0gZG95LCB5ID0gdGVtcF9jKSkgKyAKICBmYWNldF93cmFwKHJlZ2lvbn4uKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IHNpdGVfdGVtcHMyLAogICAgICAgICAgICAgYWVzKHggPSBkb3ksIHkgPSBjb2xsZWN0aW9uX3RlbXAsIGNvbG91ciA9IHNpdGUpLAogICAgICAgICAgICAgc2l6ZSA9IDMpICsKICBnZW9tX2xpbmUoKSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2l0ZV9jb2xzKSArIAogIGxhYnMoeCA9ICJEYXkgb2YgdGhlIFllYXIiLCAKICAgICAgIHkgPSAiTWVhbiBEYWlseSBUZW1wLiAowrBDKSIpICsgCiAgdGhlbWVfbWF0dF9mYWNldHMoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgoKRXhhY3QgbG9jYXRpb25zIGZvciB0aGUgc2l0ZXMgYXJlIHByb3ZpZGVkIGhlcmUuIAoKYGBge3Igc2l0ZS10YWJsZX0Kc2l0ZV9kYXRhICU+JSAgCiAgYXJyYW5nZShsYXQpICU+JSAgCiAgc2VsZWN0KCJTaXRlIiA9IHNpdGUsICJSZWdpb24iID0gcmVnaW9uLCAiTGF0IiA9IGxhdCwgIkxvbmciID0gbG9uZykgJT4lIAogIGtuaXRyOjprYWJsZShhbGlnbiA9ICJjIikKYGBgCgpOZXN0ZWQgd2l0aGluIGVhY2ggb2YgdGhlIHRocmVlIHJlZ2lvbnMgKFNvdXRoLCBDZW50cmFsLCBhbmQgTm9ydGhlcm4gcmVnaW9ucykgYXJlIHBhaXJzIG9mIGxvdyBhbmQgaGlnaCBzYWxpbml0eSBzaXRlczogICAgCgpgYGB7ciBzYWwtdGFibGV9CmRhdGEuZnJhbWUoIlJlZ2lvbiIgPSBjKCJTb3V0aCIsICJDZW50cmFsIiwgIk5vcnRoIiksCiAgICAgICAgICAgIkxvdyBTYWxpbml0eSIgPSBjKCJGdC4gSGFtZXIiLCAiR2FuZXkncyBXaGFyZiIsICJSaXRjaGllIFdoYXJmIiksCiAgICAgICAgICAgIkhpZ2ggU2FsaW5pdHkiID0gYygiTWFuYXRlZSBSaXZlciIsICJUeWxlciBDb3ZlIiwgIlN0LiBUaG9tYXMgZGUgS2VudCBXaGFyZiIpKSAlPiUgCiAga25pdHI6OmthYmxlKGFsaWduID0gImMiKQpgYGAKClwgCgpUaGVyZSBhcmUgZmFpcmx5IHdlbGwtZXN0YWJsaXNoZWQgZGl2ZXJnZW5jZXMgYmV0d2VlbiBoaWdoIHNhbGluaXR5IGFuZCBsb3cgc2FsaW5pdHkgcG9wdWxhdGlvbnMgb2YgKkFjYXJ0aWEgdG9uc2EqLiBUaGVzZSBzZXRzIG9mIGdlb2dyYXBoaWNhbGx5IHByb3hpbWF0ZSBidXQgaXNvbGF0ZWQgcG9wdWxhdGlvbnMgcHJvdmlkZSBpbmRlcGVuZGVudCBjb21wYXJpc29ucyBvZiB0aGUgZWZmZWN0cyBvZiBzZWFzb25hbGl0eS4gU2hvd24gaGVyZSBhcmUgdGhlIGNvbGxlY3Rpb24gY29uZGl0aW9ucyBmb3IgdGhlc2UgcGFpcnMgb2Ygc2l0ZXMuIFRlbXBlcmF0dXJlIHdhcyB0eXBpY2FsbHkgc2ltaWxhciBhY3Jvc3MgdGhlIHBhaXJzIHdpdGhpbiBlYWNoIGNvbGxlY3Rpb24sIHdoaWxlIHNhbGluaXR5IGRpZmZlcmVuY2VzIHdlcmUgZmFpcmx5IHN0YWJsZSBhY3Jvc3MgY29sbGVjdGlvbnMuIAoKYGBge3Igc2Vhc29uLXNhbC1jb21wcywgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9OH0Kc2Vhc29uX2NvbHMgPSBjKCJlYXJseSIgPSAiZ3JleTc1IiwgCiAgICAgICAgICAgICAgICAicGVhayIgPSAiZ3JleTUwIiwgCiAgICAgICAgICAgICAgICAibGF0ZSIgPSAiZ3JleTI1IikKCnNhbF9yZWdpb25zID0gZGF0YS5mcmFtZShyZWdpb24gPSByZXAoYygiU291dGgiLCAiQ2VudHJhbCIsICJOb3J0aCIpLCBlYWNoID0gMiksIAogICAgICAgICAgICAgICAgICAgICAgICAgc2l0ZSA9IGMoIkZ0LiBIYW1lciIsICJNYW5hdGVlIFJpdmVyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR2FuZXkncyBXaGFyZiIsICJUeWxlciBDb3ZlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUml0Y2hpZSBXaGFyZiIsICJTdC4gVGhvbWFzIGRlIEtlbnQgV2hhcmYiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIHNhbGluaXR5ID0gYygibG93IiwgImhpZ2giKSkKCnNhbF9jb21wcyA9IGZ1bGxfZGF0YSAlPiUgCiAgZmlsdGVyKHNpdGUgJWluJSBzYWxfcmVnaW9ucyRzaXRlKSAlPiUgCiAgaW5uZXJfam9pbihzYWxfcmVnaW9ucywgYnkgPSBjKCJzaXRlIikpICU+JSAKICBzZWxlY3QoIHJlZ2lvbiA9IHJlZ2lvbi55LCBzaXRlLCBzYWxpbml0eSwgc2Vhc29uLCBkb3ksIGNvbGxlY3Rpb25fdGVtcCwgY29sbGVjdGlvbl9zYWxpbml0eSwKICAgICAgICAgIHNpemUsIGN0bWF4LCB3YXJtaW5nX3RvbCkgJT4lIAogIG11dGF0ZShzYWxpbml0eSA9IGZjdF9yZWxldmVsKHNhbGluaXR5LCAibG93IiwgImhpZ2giKSwKICAgICAgICAgcmVnaW9uID0gZmN0X3JlbGV2ZWwocmVnaW9uLCAiU291dGgiLCAiQ2VudHJhbCIsICJOb3J0aCIpKQoKc2FsX2NvbXBfdGVtcHMgPSBzYWxfY29tcHMgJT4lICAKICBzZWxlY3Qoc2FsaW5pdHksIHNlYXNvbiwgcmVnaW9uLCBjb2xsZWN0aW9uX3RlbXAsIGNvbGxlY3Rpb25fc2FsaW5pdHkpICU+JSAKICBkaXN0aW5jdCgpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBzYWxpbml0eSwgeSA9IGNvbGxlY3Rpb25fdGVtcCwgY29sb3VyID0gc2Vhc29uLCBncm91cCA9IHNlYXNvbikpICsgCiAgZmFjZXRfd3JhcChyZWdpb25+LikgKyAKICBnZW9tX2xpbmUobGluZXdpZHRoID0gMS41KSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDQpICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzZWFzb25fY29scykgKyAKICBsYWJzKHkgPSAiQ29sbGVjdGlvbiBUZW1wLiAowrBDKSIsCiAgICAgICB4ID0gIiIpICsgCiAgdGhlbWVfbWF0dF9mYWNldHMoYmFzZV9zaXplID0gMTQpCgpzYWxfY29tcF9zYWwgPSBzYWxfY29tcHMgJT4lICAKICBzZWxlY3Qoc2FsaW5pdHksIHNlYXNvbiwgcmVnaW9uLCBjb2xsZWN0aW9uX3RlbXAsIGNvbGxlY3Rpb25fc2FsaW5pdHkpICU+JSAKICBkaXN0aW5jdCgpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBzYWxpbml0eSwgeSA9IGNvbGxlY3Rpb25fc2FsaW5pdHksIGNvbG91ciA9IHNlYXNvbiwgZ3JvdXAgPSBzZWFzb24pKSArIAogIGZhY2V0X3dyYXAocmVnaW9ufi4pICsgCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDEuNSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSA0KSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2Vhc29uX2NvbHMpICsgCiAgbGFicyh5ID0gIkNvbGxlY3Rpb24gU2FsaW5pdHkgKHBzdSkiLAogICAgICAgeCA9ICJTYWxpbml0eSIpICsgCiAgdGhlbWVfbWF0dF9mYWNldHMoYmFzZV9zaXplID0gMTQpCgpnZ2FycmFuZ2Uoc2FsX2NvbXBfdGVtcHMsIHNhbF9jb21wX3NhbCwgbnJvdyA9IDIsIGNvbW1vbi5sZWdlbmQgPSBULCBsZWdlbmQgPSAicmlnaHQiKQoKIyBzYWxfY29tcHMgJT4lICAKIyAgIHNlbGVjdChzaXRlLCBzYWxpbml0eSwgc2Vhc29uLCByZWdpb24sIGNvbGxlY3Rpb25fdGVtcCwgY29sbGVjdGlvbl9zYWxpbml0eSkgJT4lIAojICAgZGlzdGluY3QoKSAlPiUgCiMgICBnZ3Bsb3QoYWVzKHggPSBjb2xsZWN0aW9uX3NhbGluaXR5LCB5ID0gY29sbGVjdGlvbl90ZW1wLCBjb2xvdXIgPSBzaXRlKSkgKyAKIyAgIGZhY2V0X2dyaWQocmVnaW9ufi4pICsgCiMgICBnZW9tX3BvaW50KHNpemUgPSA0KSArIAojICAgI3N0YXRfZWxsaXBzZSgpICsKIyAgICNnZW9tX3BhdGgoYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMSwgImluY2hlcyIpLCB0eXBlID0gImNsb3NlZCIpKSArIAojICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiMgICB0aGVtZV9tYXR0X2ZhY2V0cyhiYXNlX3NpemUgPSAxNCkKYGBgCgpUaGUgbGF0aXR1ZGluYWwgZ3JhZGllbnQgY292ZXJzIGEgd2lkZSByYW5nZSBvZiBzZWFzb25hbGl0eS4gU2hvd24gYmVsb3cgaXMgdGhlIHRlbXBlcmF0dXJlIHJhbmdlLiBXaGlsZSBiYXNlZCBvbiBjb2xsZWN0aW9uIHRlbXBlcmF0dXJlcywgYW5kIHRoZXJlZm9yZSBhbiB1bmRlcmVzdGltYXRlIG9mIHRoZSB0b3RhbCBzZWFzb25hbCByYW5nZSBvZiB0ZW1wZXJhdHVyZXMsIHRoZXNlIHBhdHRlcm5zIGFyZSByZXByZXNlbnRhdGl2ZSBvZiB0aGUgZXhwZWN0ZWQgbGF0aXR1ZGluYWwgZ3JhZGllbnQgaW4gc2Vhc29uYWxpdHkuIAoKYGBge3IgbGF0LXRlbXAtcmFuZ2UtcGxvdCwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NX0Kc2l0ZV90ZW1wcyAlPiUgCiAgZ3JvdXBfYnkoc2l0ZSwgbGF0KSAlPiUgIAogIHN1bW1hcmlzZSh0ZW1wX3JhbmdlID0gbWF4KGNvbGxlY3Rpb25fdGVtcCkgLSBtaW4oY29sbGVjdGlvbl90ZW1wKSkgJT4lICAKICBnZ3Bsb3QoYWVzKHggPSBsYXQsIHkgPSB0ZW1wX3JhbmdlKSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBzaXRlKSwKICAgICAgICAgICAgIHNpemUgPSAzKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiAgbGFicyh4ID0gIkxhdGl0dWRlIiwgCiAgICAgICB5ID0gIkNvbGxlY3Rpb24gVGVtcC4gUmFuZ2UgKMKwQykiKSArIAogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCmBgYAoKCiMjIFBoZW5vdHlwaWMgTWVhc3VyZW1lbnRzIAoKIyMjIENyaXRpY2FsIFRoZXJtYWwgTGltaXRzCgpBIHRvdGFsIG9mIGByIGRpbShhbGxfZGF0YSlbMV1gIGluZGl2aWR1YWxzIHdlcmUgZXhhbWluZWQuIENyaXRpY2FsIHRoZXJtYWwgbGltaXRzIGFuZCBib2R5IHNpemUgbWVhc3VyZW1lbnRzIHdlcmUgbWFkZSBiZWZvcmUgaW5kaXZpZHVhbHMgd2VyZSBwcmVzZXJ2ZWQgaW4gZXRoYW5vbC4gV2UgZXhjbHVkZWQgZGF0YSBmb3IgYHIgZGltKGV4Y2x1ZGVkKVsxXWAgaW5kaXZpZHVhbHMsIGRldGFpbGVkIGJlbG93LiBUaGVzZSBpbmRpdmlkdWFscyBoYWQgZWl0aGVyIHZlcnkgbG93IENUbWF4IG9yIHdlcmUsIHVwb24gcmUtZXhhbWluYXRpb24gb2YgcGhvdG9ncmFwaHMsIGlkZW50aWZpZWQgYXMganV2ZW5pbGVzIGluc3RlYWQgb2YgbWF0dXJlIGZlbWFsZXMuIFdpdGggdGhlc2UgaW5kaXZpZHVhbHMgZXhjbHVkZWQsICoqdGhlIGZ1bGwgZGF0YSBzZXQgY29udGFpbnMgYHIgZGltKGZ1bGxfZGF0YSlbMV1gIHBoZW5vdHlwZWQgaW5kaXZpZHVhbHMqKi4gICAKCmBgYHtyIGV4Y2x1ZGVkLWluZHN9CmV4Y2x1ZGVkICU+JSAKICBzZWxlY3QocmVnaW9uLCBzaXRlLCBzZWFzb24sIGNvbGxlY3Rpb25fdGVtcCwgY29sbGVjdGlvbl9zYWxpbml0eSwgcmVwbGljYXRlLCB0dWJlLCBjdG1heCwgc2l6ZSkgJT4lIAogIGtuaXRyOjprYWJsZShhbGlnbiA9ICJjIikKYGBgCgpDcml0aWNhbCB0aGVybWFsIG1heGltYSAoQ1RtYXgpIHdhcyBtZWFzdXJlZCB1c2luZyBhIGN1c3RvbSBzZXR1cC4gVGhlIG1ldGhvZCB1c2VzIGEgc3RhbmRhcmQgZHluYW1pYyByYW1waW5nIGFzc2F5IHRvIGRldGVybWluZSB0aGUgbWF4aW11bSB0ZW1wZXJhdHVyZSBpbmRpdmlkdWFscyBjb3VsZCBzdXN0YWluIG5vcm1hbCBmdW5jdGlvbmluZy4gVGhpcyBkaWZmZXJzIGZyb20gbGV0aGFsIHRlbXBlcmF0dXJlcywgYW5kIGluZGVlZCwgYWxsIGluZGl2aWR1YWxzIG9ic2VydmVkIHNvIGZhciByZWNvdmVyZWQgZm9sbG93aW5nIHRoZSBhc3NheS4KCkluZGl2aWR1YWxzIHdlcmUgcmVzdGVkIGZvciBvbmUgaG91ciBhZnRlciBjb2xsZWN0aW9uIGJlZm9yZSB0aGUgYXNzYXkuIER1cmluZyB0aGUgYXNzYXksIGNvcGVwb2RzIHdlcmUgaGVsZCBpbiBhcnRpZmljaWFsIHNlYXdhdGVyLCBjb21wb3NlZCBvZiBib3R0bGVkIHNwcmluZyB3YXRlciBhbmQgSW5zdGFudCBPY2VhbiBzYWx0IG1peCBhZGp1c3RlZCB0byBtYXRjaCBjb2xsZWN0aW9uIHNhbGluaXRpZXMuIER1cmluZyB0aGUgYXNzYXksIHNldmVyYWwgJ2NvbnRyb2wnIGluZGl2aWR1YWxzIHdlcmUgbWFpbnRhaW5lZCBpbiB0aGlzIHNvbHV0aW9uIGF0IGFtYmllbnQgdGVtcGVyYXR1cmVzIHdpdGhvdXQgdGhlIHRlbXBlcmF0dXJlIHJhbXAgdG8gZW5zdXJlIHRoYXQgdGhlcmUgd2FzIG5vIGJhY2tncm91bmQgbW9ydGFsaXR5LiBXaGVuIHNvcnRpbmcgaW5kaXZpZHVhbHMgZnJvbSB0aGUgcGxhbmt0b24gdG93IGNvbnRlbnRzLCB0aGV5IHdlcmUgaGVsZCBpbiBhIDUwOjUwIG1peCBvZiA2MCB1bSBmaWx0ZXJlZCB3YXRlciBmcm9tIHRoZSBjb2xsZWN0aW9uIHNpdGUgYW5kIGFydGlmaWNpYWwgc2Vhd2F0ZXIgYXMgYW4gYWRkaXRpb25hbCBhY2NsaW1hdGlvbiBzdGVwLiAKClNhbXBsZSBzaXplcyB2YXJpZWQgc2xpZ2h0bHkgYWNyb3NzIGV4cGVyaW1lbnRzLCBidXQgbW9zdCBzaXRlcyBoYWQgMjAgaW5kaXZpZHVhbHMgbWVhc3VyZWQgcGVyIHNlYXNvbi4gVGhlIG1ham9yIGV4Y2VwdGlvbnMgd2VyZSB0aGUgZWFybHkgc2FtcGxlcyBmcm9tIHRoZSBGbG9yaWRhIHNpdGVzIGFuZCB0aGUgbGF0ZSBzYW1wbGUgZnJvbSBTYXd5ZXIgUGFyayAoTWFpbmUpLiBPbmx5IHR3byBzZXRzIG9mIHNhbXBsZXMgKHBlYWsgYW5kIGxhdGUpIHdlcmUgY29sbGVjdGVkIGZyb20gRm9ydCBIYW1lciBhbmQgTWFuYXRlZSBSaXZlci4gTm8gc2FtcGxlcyB3ZXJlIGNvbGxlY3RlZCBmcm9tIEtleSBMYXJnbyBmb3IgdGhpcyBwcm9qZWN0LCBhcyAqQWNhcnRpYSB0b25zYSogd2Fzbid0IHByZXNlbnQgaW4gdGhlIHdhdGVyIGR1cmluZyB0aGUgcGVhayBzZWFzb24sIGxpa2VseSBkdWUgdG8gdGhlIHJlY2VudCBleHRyZW1lIGhlYXQgZXZlbnQuIFRoZSBsYXRlIHNlYXNvbiBjb2xsZWN0aW9uIGZyb20gU2F3eWVyIFBhcmsgb2NjdXJyZWQgYWZ0ZXIgKkFjYXJ0aWEgdG9uc2EqIGFidW5kYW5jZSBkZWNyZWFzZWQuIFNhbXBsZXMgZnJvbSB0aGlzIHBlcmlvZCB3ZXJlIGRvbWluYXRlZCBieSAqQWNhcnRpYSBodWRzb25pY2EqIGluc3RlYWQuIAoKYGBge3Igc2FtcGxlLXNpemUtcGxvdCwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTV9CmdncGxvdChmdWxsX2RhdGEsIGFlcyh4ID0gc2l0ZSwgZmlsbCA9IHNpdGUpKSArIAogIGZhY2V0X3dyYXAoc2Vhc29ufi4pICsgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYygwLDIwKSwKICAgICAgICAgICAgIGNvbG91ciA9ICJncmV5NzAiKSArIAogIGdlb21fYmFyKCkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9tYXR0KCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGxpbmV3aWR0aCA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgpTaG93biBiZWxvdyBhcmUgdGhlIG1lYXN1cmVkIENUbWF4IHZhbHVlcy4gTm90ZTogQ1RtYXggdmFsdWVzIGZvciB0aGUgZWFybHkgc2Vhc29uIEtleSBMYXJnbyBjb3BlcG9kcyB3ZXJlIGNvbGxlY3RlZCBhdCB0aGUgZW5kIG9mIEZlYnJ1YXJ5IDIwMjMgYXMgcGFydCBvZiBhIHNlcGFyYXRlIHByb2plY3QuIEJvZHkgc2l6ZSB2YWx1ZXMgd2VyZSBub3QgbWVhc3VyZWQgZHVyaW5nIHRoaXMgcHJvamVjdCwgbm9yIHdlcmUgY29wZXBvZHMgaW5kaXZpZHVhbGx5IHByZXNlcnZlZCBhZnRlciB0aGUgZXhwZXJpbWVudHMuIFRoZXNlIGVhcmx5IHNlYXNvbiBDVG1heCB2YWx1ZXMgYXJlIGluY2x1ZGVkIGFzIGEgcG9pbnQgb2YgY29tcGFyaXNvbi4gSW5kaXZpZHVhbCBtZWFzdXJlbWVudHMgYXJlIHNob3duIGluIHNtYWxsIHBvaW50cyBmb3IgZWFjaCBjb2xsZWN0aW9uLiBUaGUgbGFyZ2UgcG9pbnRzIGluZGljYXRlIHRoZSBtZWFuIHZhbHVlcyBmb3IgZWFjaCBjb2xsZWN0aW9uLiAKCmBgYHtyIHNlYXNvbmFsLWN0LW1heH0KbWVhbl9jdG1heCA9IGZ1bGxfZGF0YSAlPiUgCiAgZ3JvdXBfYnkoc2l0ZSwgc2Vhc29uLCBkb3ksIGNvbGxlY3Rpb25fdGVtcCkgJT4lIAogIHN1bW1hcml6ZShtZWFuX2N0bWF4ID0gbWVhbihjdG1heCksCiAgICAgICAgICAgIG1lZGlhbl9jdG1heCA9IG1lZGlhbihjdG1heCkpCgpnZ3Bsb3QoZnVsbF9kYXRhLCBhZXMoeCA9IHNlYXNvbiwgeSA9IGN0bWF4LCBjb2xvdXIgPSBzaXRlKSkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IG1lYW5fY3RtYXgsIAogICAgICAgICAgICBhZXMoeSA9IG1lYW5fY3RtYXgsIGdyb3VwID0gc2l0ZSksCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjQpLAogICAgICAgICAgICBsaW5ld2lkdGggPSAxKSArIAogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZShqaXR0ZXIud2lkdGggPSAwLjEsIGppdHRlci5oZWlnaHQgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb2RnZS53aWR0aCA9IDAuNCksCiAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBtZWFuX2N0bWF4LCAKICAgICAgICAgICAgIGFlcyh5ID0gbWVhbl9jdG1heCksCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC40KSwKICAgICAgICAgICAgIHNpemUgPSA0KSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2l0ZV9jb2xzKSArIAogIGxhYnMoeSA9ICJDVG1heCAowrBDKSIsCiAgICAgICB4ID0gIlNlYXNvbiIpICsKICB0aGVtZV9tYXR0KCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCAKICAgICAgICBsZWdlbmQudGl0bGUuYWxpZ24gPSAwLjEyNSkKYGBgCgpgYGB7ciBkb3ktY3QtbWF4LCBpbmNsdWRlID0gRn0KIyBUaGUgc2FtZSBkYXRhIGlzIHNob3duIGJlbG93LCBwbG90dGVkIGFnYWluc3QgZGF5IG9mIHRoZSB5ZWFyIGluc3RlYWQgb2Ygc2Vhc29uLiBUaGlzIGFjY291bnRzIGZvciB0aGUgdmFyaWFibGUgdGltaW5nIG9mIGNvbGxlY3Rpb25zIGFjcm9zcyByZWdpb25zIChlLmcuIC0gdGhlIGNvbXByZXNzZWQgY29sbGVjdGlvbnMgZnJvbSB0aGUgTm9ydGhlcm4gc2l0ZXMgdG8gYWNjb21vZGF0ZSB0aGUgZWFybGllciBvbnNldCBvZiBjb2xkIHRlbXBlcmF0dXJlcykuIAoKZ2dwbG90KGZpbHRlcihmdWxsX2RhdGEsIHNpdGUgIT0gIktleSBMYXJnbyIpLCBhZXMoeCA9IGRveSwgeSA9IGN0bWF4LCBjb2xvdXIgPSBzaXRlKSkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IGZpbHRlcihtZWFuX2N0bWF4LCBzaXRlICE9ICJLZXkgTGFyZ28iKSwgCiAgICAgICAgICAgIGFlcyh5ID0gbWVkaWFuX2N0bWF4LCBncm91cCA9IHNpdGUpLAogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC40KSwKICAgICAgICAgICAgbGluZXdpZHRoID0gMSkgKyAKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2Uoaml0dGVyLndpZHRoID0gMC4xLCBqaXR0ZXIuaGVpZ2h0ID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9kZ2Uud2lkdGggPSAwLjQpLAogICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gZmlsdGVyKG1lYW5fY3RtYXgsIHNpdGUgIT0gIktleSBMYXJnbyIpLCAKICAgICAgICAgICAgIGFlcyh5ID0gbWVkaWFuX2N0bWF4KSwKICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjQpLAogICAgICAgICAgICAgc2l6ZSA9IDQpICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiAgbGFicyh5ID0gIkNUbWF4ICjCsEMpIiwKICAgICAgIHggPSAiU2Vhc29uIikgKwogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIAogICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAuMTI1KQpgYGAKCkNUbWF4IGRhdGEgZm9yIGVhY2ggaW5kaXZpZHVhbCBzaXRlIGlzIHNob3duIGJlbG93LCBwbG90dGVkIGFnYWluc3QgZGF5IG9mIHRoZSB5ZWFyLiAKCmBgYHtyIGN0bWF4LWluZC1wb3BzLWRveSwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KZ2dwbG90KGZ1bGxfZGF0YSwgYWVzKHggPSBkb3ksIHkgPSBjdG1heCwgY29sb3VyID0gc2l0ZSkpICsgCiAgZmFjZXRfd3JhcCgufnNpdGUsIHNjYWxlcyA9ICJmcmVlIikgKyAKICBnZW9tX2xpbmUoZGF0YSA9IG1lYW5fY3RtYXgsIAogICAgICAgICAgICBhZXMoeSA9IG1lYW5fY3RtYXgsIGdyb3VwID0gc2l0ZSksCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjQpLAogICAgICAgICAgICBsaW5ld2lkdGggPSAzLCBhbHBoYSA9IDAuNSkgKyAKICAjIGdlb21fbGluZShkYXRhID0gbWVhbl9jdG1heCwgCiAgIyAgICAgICAgICAgYWVzKHkgPSBjb2xsZWN0aW9uX3RlbXAsIGdyb3VwID0gc2l0ZSksCiAgIyAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNCksCiAgIyAgICAgICAgICAgbGluZXdpZHRoID0gMiwKICAjICAgICAgICAgICBjb2xvdXIgPSAiZ3JleSIpICsgCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKGppdHRlci53aWR0aCA9IDAuMSwgaml0dGVyLmhlaWdodCA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvZGdlLndpZHRoID0gMC40KSwKICAgICAgICAgICAgIGFscGhhID0gMC44KSArIAogICMgZ2VvbV9wb2ludChkYXRhID0gbWVhbl9jdG1heCwgCiAgIyAgICAgICAgICAgIGFlcyh5ID0gbWVkaWFuX2N0bWF4KSwKICAjICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNCksCiAgIyAgICAgICAgICAgIHNpemUgPSA0KSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2l0ZV9jb2xzKSArIAogIGxhYnMoeSA9ICJDVG1heCAowrBDKSIsCiAgICAgICB4ID0gIkRheSBvZiBZZWFyIikgKwogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgCiAgICAgICAgbGVnZW5kLnRpdGxlLmFsaWduID0gMC4xMjUpCmBgYAoKYGBge3IgY3RtYXgtaW5kLXBvcHMtc2Vhc29uLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02LCBpbmNsdWRlID0gRn0KZ2dwbG90KGZ1bGxfZGF0YSwgYWVzKHggPSBzZWFzb24sIHkgPSBjdG1heCwgY29sb3VyID0gc2l0ZSkpICsgCiAgZmFjZXRfd3JhcCgufnNpdGUsIHNjYWxlcyA9ICJmcmVlX3kiKSArIAogIGdlb21fbGluZShkYXRhID0gbWVhbl9jdG1heCwgCiAgICAgICAgICAgIGFlcyh5ID0gbWVkaWFuX2N0bWF4LCBncm91cCA9IHNpdGUpLAogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC40KSwKICAgICAgICAgICAgbGluZXdpZHRoID0gMywgYWxwaGEgPSAwLjUpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBtZWFuX2N0bWF4LCAKICAgICAgICAgICAgYWVzKHkgPSBjb2xsZWN0aW9uX3RlbXAsIGdyb3VwID0gc2l0ZSksCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjQpLAogICAgICAgICAgICBsaW5ld2lkdGggPSAyLAogICAgICAgICAgICBjb2xvdXIgPSAiZ3JleSIpICsgCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKGppdHRlci53aWR0aCA9IDAuMSwgaml0dGVyLmhlaWdodCA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvZGdlLndpZHRoID0gMC40KSwKICAgICAgICAgICAgIGFscGhhID0gMC44KSArIAogICMgZ2VvbV9wb2ludChkYXRhID0gbWVhbl9jdG1heCwgCiAgIyAgICAgICAgICAgIGFlcyh5ID0gbWVkaWFuX2N0bWF4KSwKICAjICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNCksCiAgIyAgICAgICAgICAgIHNpemUgPSA0KSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2l0ZV9jb2xzKSArIAogIGxhYnMoeSA9ICJDVG1heCAowrBDKSIsCiAgICAgICB4ID0gIlNlYXNvbiIpICsKICB0aGVtZV9tYXR0KCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIAogICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAuMTI1KQpgYGAKCiMjIyBXYXJtaW5nIHRvbGVyYW5jZQoKV2FybWluZyB0b2xlcmFuY2UgKHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlcm1hbCBsaW1pdHMgYW5kIGVudmlyb25tZW50YWwgdGVtcGVyYXR1cmVzKSBpcyBhIGNvbW1vbmx5IHVzZWQgbWV0cmljIG9mIGNsaW1hdGUgdnVsbmVyYWJpbGl0eS4gV2UgY2FsY3VsYXRlZCB0aGlzIGFzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gbWVhc3VyZWQgQ1RtYXggdmFsdWVzIGFuZCB0aGUgY29sbGVjdGlvbiB0ZW1wZXJhdHVyZS4gU21hbGxlciB3YXJtaW5nIHRvbGVyYW5jZSB2YWx1ZXMgaW5kaWNhdGUgdGhhdCBwb3B1bGF0aW9ucyB3ZXJlIG5lYXJlciB0byB0aGVpciB1cHBlciB0aGVybWFsIGxpbWl0cywgYW5kIG1heSB0aGVyZWZvcmUgYmUgbW9yZSB2dWxuZXJhYmxlIHRvIGFkZGl0aW9uYWwgd2FybWluZy4gCgpgYGB7ciBzZWFzb25hbC13YXJtaW5nLXRvbH0KbWVhbl93dCA9IGZ1bGxfZGF0YSAlPiUgCiAgZ3JvdXBfYnkoc2l0ZSwgc2Vhc29uKSAlPiUgCiAgc3VtbWFyaXplKG1lYW5fd3QgPSBtZWFuKHdhcm1pbmdfdG9sKSwKICAgICAgICAgICAgbWVkaWFuX3d0ID0gbWVkaWFuKHdhcm1pbmdfdG9sKSkKCmdncGxvdChmdWxsX2RhdGEsIGFlcyh4ID0gc2Vhc29uLCB5ID0gd2FybWluZ190b2wsIGNvbG91ciA9IHNpdGUpKSArIAogIGdlb21fbGluZShkYXRhID0gbWVhbl93dCwgCiAgICAgICAgICAgIGFlcyh5ID0gbWVhbl93dCwgZ3JvdXAgPSBzaXRlKSwKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNCksCiAgICAgICAgICAgIGxpbmV3aWR0aCA9IDEpICsgCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKGppdHRlci53aWR0aCA9IDAuMSwgaml0dGVyLmhlaWdodCA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvZGdlLndpZHRoID0gMC40KSwKICAgICAgICAgICAgIGFscGhhID0gMC4zKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IG1lYW5fd3QsIAogICAgICAgICAgICAgYWVzKHkgPSBtZWFuX3d0KSwKICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjQpLAogICAgICAgICAgICAgc2l6ZSA9IDQpICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiAgbGFicyh5ID0gIldhcm1pbmcgVG9sZXJhbmNlICjCsEMpIiwKICAgICAgIHggPSAiU2Vhc29uIikgKwogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIAogICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAuMTI1KQpgYGAKCiMjIyBCb2R5IFNpemUKCkZvbGxvd2luZyB0aGUgQ1RtYXggYXNzYXksIGluZGl2aWR1YWxzIHdlcmUgcGhvdG9ncmFwaGVkIGZvciBib2R5IHNpemUgbWVhc3VyZW1lbnRzLiBQcm9zb21lIGxlbmd0aHMgd2VyZSBtZWFzdXJlZCBmcm9tIHRoZXNlIHBob3RvZ3JhcGhzIHVzaW5nIGEgc2NhbGUgbWljcm9tZXRlciBhbmQgdGhlIHNvZnR3YXJlIEltYWdlSi4gVGhlc2UgbWVhc3VyZW1lbnRzIGFyZSBzaG93biBiZWxvdy4gQXMgYmVmb3JlLCBsYXJnZSBwb2ludHMgaW5kaWNhdGUgdGhlIG1lYW4gYm9keSBzaXplLiBXaGlsZSBsZXNzIGNvaGVzaXZlIHRoYW4gQ1RtYXgsIGEgZ2VuZXJhbCB0cmVuZCBvZiBpbmNyZWFzaW5nIGJvZHkgc2l6ZSB3aXRoIGxhdGl0dWRlIGFuZCB0aW1lIG9mIHllYXIgY2FuIGJlIHNlZW4uIAoKYGBge3Igc2Vhc29uYWwtYm9keS1zaXplfQptZWFuX3NpemUgPSBmdWxsX2RhdGEgJT4lIAogIGdyb3VwX2J5KHNpdGUsIHNlYXNvbiwgZG95LCBjb2xsZWN0aW9uX3RlbXApICU+JSAKICBzdW1tYXJpemUobWVhbl9zaXplID0gbWVhbihzaXplKSwKICAgICAgICAgICAgbWVkaWFuX3NpemUgPSBtZWRpYW4oc2l6ZSkpCgpnZ3Bsb3QoZnVsbF9kYXRhLCBhZXMoeCA9IHNlYXNvbiwgeSA9IHNpemUsIGNvbG91ciA9IHNpdGUpKSArIAogIGdlb21fbGluZShkYXRhID0gbWVhbl9zaXplLCAKICAgICAgICAgICAgYWVzKHkgPSBtZWFuX3NpemUsIGdyb3VwID0gc2l0ZSksCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjQpLAogICAgICAgICAgICBsaW5ld2lkdGggPSAxKSArIAogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZShqaXR0ZXIud2lkdGggPSAwLjEsIGppdHRlci5oZWlnaHQgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb2RnZS53aWR0aCA9IDAuNCksCiAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBtZWFuX3NpemUsIAogICAgICAgICAgICAgYWVzKHkgPSBtZWFuX3NpemUpLAogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNCksCiAgICAgICAgICAgICBzaXplID0gNCkgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNpdGVfY29scykgKyAKICBsYWJzKHkgPSAiUHJvc29tZSBMZW5ndGggKG1tKSIsCiAgICAgICB4ID0gIlNlYXNvbiIpICsKICB0aGVtZV9tYXR0KCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCAKICAgICAgICBsZWdlbmQudGl0bGUuYWxpZ24gPSAwLjEyNSkKYGBgCgpgYGB7ciBkb3ktYm9keS1zaXplLCBpbmNsdWRlID0gRn0KZ2dwbG90KGRyb3BfbmEoZnVsbF9kYXRhLCBzaXplKSwgYWVzKHggPSBkb3ksIHkgPSBzaXplLCBjb2xvdXIgPSBzaXRlKSkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IGRyb3BfbmEobWVhbl9zaXplLCBtZWFuX3NpemUpLCAKICAgICAgICAgICAgYWVzKHkgPSBtZWRpYW5fc2l6ZSwgZ3JvdXAgPSBzaXRlKSwKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNCksCiAgICAgICAgICAgIGxpbmV3aWR0aCA9IDEpICsgCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKGppdHRlci53aWR0aCA9IDAuMSwgaml0dGVyLmhlaWdodCA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvZGdlLndpZHRoID0gMC40KSwKICAgICAgICAgICAgIGFscGhhID0gMC4zKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IGRyb3BfbmEobWVhbl9zaXplLCBtZWFuX3NpemUpLCAKICAgICAgICAgICAgIGFlcyh5ID0gbWVkaWFuX3NpemUpLAogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNCksCiAgICAgICAgICAgICBzaXplID0gNCkgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNpdGVfY29scykgKyAKICBsYWJzKHkgPSAiUHJvc29tZSBMZW5ndGggKG1tKSIsCiAgICAgICB4ID0gIlNlYXNvbiIpICsKICB0aGVtZV9tYXR0KCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCAKICAgICAgICBsZWdlbmQudGl0bGUuYWxpZ24gPSAwLjEyNSkKYGBgCgpTaG93biBiZWxvdyBpcyB0aGUgYm9keSBzaXplIGRhdGEgZm9yIGVhY2ggaW5kaXZpZHVhbCBzaXRlLiAKCmBgYHtyIHNpemUtaW5kLXBvcHMtZG95LCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQpnZ3Bsb3QoZHJvcF9uYShmdWxsX2RhdGEsIHNpemUpLCBhZXMoeCA9IGRveSwgeSA9IHNpemUsIGNvbG91ciA9IHNpdGUpKSArIAogIGZhY2V0X3dyYXAoLn5zaXRlKSArIAogIGdlb21fbGluZShkYXRhID0gZHJvcF9uYShtZWFuX3NpemUsIG1lYW5fc2l6ZSksIAogICAgICAgICAgICBhZXMoeSA9IG1lYW5fc2l6ZSwgZ3JvdXAgPSBzaXRlKSwKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNCksCiAgICAgICAgICAgIGxpbmV3aWR0aCA9IDMsIGFscGhhID0gMC41KSArIAogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZShqaXR0ZXIud2lkdGggPSAwLjEsIGppdHRlci5oZWlnaHQgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb2RnZS53aWR0aCA9IDAuNCksCiAgICAgICAgICAgICBhbHBoYSA9IDAuOCkgKyAKICAjIGdlb21fcG9pbnQoZGF0YSA9IG1lYW5fY3RtYXgsIAogICMgICAgICAgICAgICBhZXMoeSA9IG1lZGlhbl9jdG1heCksCiAgIyAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjQpLAogICMgICAgICAgICAgICBzaXplID0gNCkgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNpdGVfY29scykgKyAKICBsYWJzKHkgPSAiUHJvc29tZSBMZW5ndGggKG1tKSIsCiAgICAgICB4ID0gIkRheSBvZiBZZWFyIikgKwogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgCiAgICAgICAgbGVnZW5kLnRpdGxlLmFsaWduID0gMC4xMjUpCmBgYAoKYGBge3Igc2l6ZS1pbmQtcG9wcy1zZWFzb24sIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTYsIGluY2x1ZGUgPSBGfQpnZ3Bsb3QoZnVsbF9kYXRhLCBhZXMoeCA9IHNlYXNvbiwgeSA9IHNpemUsIGNvbG91ciA9IHNpdGUpKSArIAogIGZhY2V0X3dyYXAoLn5zaXRlKSArIAogIGdlb21fbGluZShkYXRhID0gbWVhbl9zaXplLCAKICAgICAgICAgICAgYWVzKHkgPSBtZWRpYW5fc2l6ZSwgZ3JvdXAgPSBzaXRlKSwKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNCksCiAgICAgICAgICAgIGxpbmV3aWR0aCA9IDMsIGFscGhhID0gMC41KSArIAogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZShqaXR0ZXIud2lkdGggPSAwLjEsIGppdHRlci5oZWlnaHQgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb2RnZS53aWR0aCA9IDAuNCksCiAgICAgICAgICAgICBhbHBoYSA9IDAuOCkgKyAKICAjIGdlb21fcG9pbnQoZGF0YSA9IG1lYW5fY3RtYXgsIAogICMgICAgICAgICAgICBhZXMoeSA9IG1lZGlhbl9jdG1heCksCiAgIyAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjQpLAogICMgICAgICAgICAgICBzaXplID0gNCkgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNpdGVfY29scykgKyAKICBsYWJzKHkgPSAiUHJvc29tZSBMZW5ndGggKG1tKSIsCiAgICAgICB4ID0gIlNlYXNvbiIpICsKICB0aGVtZV9tYXR0KCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIAogICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAuMTI1KQpgYGAKCiMjIyBTYWxpbml0eSBQYWlyIENvbXBhcmlzb25zIAoKVGhlIHRocmVlIHBhaXJzIG9mIGNyb3NzLXNhbGluaXR5IGNvbXBhcmlzb25zIGRvIHNob3cgZXZpZGVuY2UgZm9yIGZpbmUtc2NhbGUgdHJhaXQgZGl2ZXJnZW5jZSwgYWx0aG91Z2ggdGhlcmUgd2FzIG5vIGNvbnNpc3RlbnQgcGF0dGVybiBpbiB0aGUgZGlyZWN0aW9uIG9yIG1hZ25pdHVkZSBvZiBkaWZmZXJlbmNlcy4gQ1RtYXggd2FzIHNpbWlsYXIgYWNyb3NzIHNpdGVzIGluIHRoZSBTb3V0aGVybiBhbmQgQ2VudHJhbCBwYWlycy4gSW4gdGhlIE5vcnRoZXJuIHBhaXIsIENUbWF4IHRlbmRlZCB0byBiZSBzbGlnaHRseSBsb3dlciBmb3IgaW5kaXZpZHVhbHMgZnJvbSB0aGUgbG93IHNhbGluaXR5IHNpdGUuIFNpemUgd2FzIG1vcmUgdmFyaWFibGUgYmV0d2VlbiB0aGUgcGFpcmVkIHNpdGVzLiBJbiB0aGUgU291dGgsIGxvdyBzYWxpbml0eSBpbmRpdmlkdWFscyB3ZXJlIGNvbnNpc3RlbnRseSBzbWFsbGVyIHRoYW4gaGlnaCBzYWxpbml0eSBpbmRpdmlkdWFscywgZGVzcGl0ZSB0aGUgc2ltaWxhciB0ZW1wZXJhdHVyZXMuIEluIHRoZSBDZW50cmFsIHBhaXIsIGluZGl2aWR1YWxzIGZyb20gdGhlIGxvdyBzYWxpbml0eSBzaXRlIHRlbmRlZCB0byBiZSBzbGlnaHRseSBsYXJnZXIgdGhhbiB0aG9zZSBmcm9tIHRoZSBoaWdoIHNhbGluaXR5IHNpdGUsIGFsdGhvdWdoIHRoaXMgdmFyaWVkIHNlYXNvbmFsbHkuIFNpemVzIHRlbmRlZCB0byBiZSBtb3JlIHNpbWlsYXIgYWNyb3NzIHRoZSBjb2xsZWN0aW9ucyBmcm9tIHRoZSBOb3J0aGVybiBwYWlyLiAKCmBgYHtyIHNhbC1wYWlyLXRyYWl0c30Kc2FsX2NvbXBfY3RtYXhfcGxvdCA9IHNhbF9jb21wcyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gc2FsaW5pdHksIHkgPSBjdG1heCwgY29sb3VyID0gc2Vhc29uLCBncm91cCA9IHNlYXNvbikpICsgCiAgZmFjZXRfd3JhcChyZWdpb25+LikgKyAKICBnZW9tX3BvaW50KHNpemUgPSAyLAogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMikpICsgCiAgI2dlb21fbGluZShzaXplID0gMS41KSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2Vhc29uX2NvbHMpICsgCiAgbGFicyh5ID0gIkNUbWF4ICjCsEMpIiwKICAgICAgIHggPSAiIikgKyAKICB0aGVtZV9tYXR0X2ZhY2V0cyhiYXNlX3NpemUgPSAxNCkKCnNhbF9jb21wX3NpemVfcGxvdCA9IHNhbF9jb21wcyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gc2FsaW5pdHksIHkgPSBzaXplLCBjb2xvdXIgPSBzZWFzb24sIGdyb3VwID0gc2Vhc29uKSkgKyAKICBmYWNldF93cmFwKHJlZ2lvbn4uKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDIsIAogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMikpICsgCiAgI2dlb21fbGluZShzaXplID0gMS41KSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2Vhc29uX2NvbHMpICsgCiAgbGFicyh5ID0gIlByb3NvbWUgTGVuZ3RoIChtbSkiLAogICAgICAgeCA9ICIiKSArIAogIHRoZW1lX21hdHRfZmFjZXRzKGJhc2Vfc2l6ZSA9IDE0KQoKZ2dhcnJhbmdlKHNhbF9jb21wX2N0bWF4X3Bsb3QsIHNhbF9jb21wX3NpemVfcGxvdCwgbnJvdyA9IDIsIGNvbW1vbi5sZWdlbmQgPSBULCBsZWdlbmQgPSAicmlnaHQiKQoKIyMjCgpzYWxfY29tcF9jdG1heC5tb2RlbCA9IGxtKGN0bWF4IH4gY29sbGVjdGlvbl90ZW1wLCBkYXRhID0gc2FsX2NvbXBzKQojIHN1bW1hcnkoY3RtYXhfdGVtcC5tb2RlbCkKIyBjYXI6OkFub3ZhKGN0bWF4X3RlbXAubW9kZWwpCnNhbF9jb21wX2N0bWF4X3Jlc2lkcyA9IHJlc2lkdWFscyhzYWxfY29tcF9jdG1heC5tb2RlbCkKCnNhbF9jb21wX3NpemUubW9kZWwgPSBsbShzaXplIH4gY29sbGVjdGlvbl90ZW1wLCBkYXRhID0gc2FsX2NvbXBzKQojIHN1bW1hcnkoc2l6ZV90ZW1wLm1vZGVsKQojIGNhcjo6QW5vdmEoc2l6ZV90ZW1wLm1vZGVsKQpzYWxfY29tcF9zaXplX3Jlc2lkcyA9IHJlc2lkdWFscyhzYWxfY29tcF9zaXplLm1vZGVsKQoKc2FsX2NvbXBfY3RtYXhfcmVzaWRfcGxvdCA9IHNhbF9jb21wcyAlPiUKICBtdXRhdGUoY3RtYXhfcmVzaWRzID0gc2FsX2NvbXBfY3RtYXhfcmVzaWRzLAogICAgICAgICBzaXplX3Jlc2lkcyA9IHNhbF9jb21wX3NpemVfcmVzaWRzKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzYWxpbml0eSwgeSA9IGN0bWF4X3Jlc2lkcywgY29sb3VyID0gc2Vhc29uLCBncm91cCA9IHNlYXNvbikpICsKICBmYWNldF93cmFwKHJlZ2lvbn4uKSArCiAgZ2VvbV9wb2ludChzaXplID0gMiwKICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpKSArCiAgI2dlb21fbGluZShzaXplID0gMS41KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzZWFzb25fY29scykgKwogIGxhYnMoeSA9ICJDVG1heCBcblJlc2lkdWFscyIsCiAgICAgICB4ID0gIiIpICsKICB0aGVtZV9tYXR0X2ZhY2V0cyhiYXNlX3NpemUgPSAxNCkKCnNhbF9jb21wX3NpemVfcmVzaWRfcGxvdCA9IHNhbF9jb21wcyAlPiUKICBtdXRhdGUoY3RtYXhfcmVzaWRzID0gc2FsX2NvbXBfY3RtYXhfcmVzaWRzLAogICAgICAgICBzaXplX3Jlc2lkcyA9IHNhbF9jb21wX3NpemVfcmVzaWRzKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzYWxpbml0eSwgeSA9IHNpemVfcmVzaWRzLCBjb2xvdXIgPSBzZWFzb24sIGdyb3VwID0gc2Vhc29uKSkgKwogIGZhY2V0X3dyYXAocmVnaW9ufi4pICsKICBnZW9tX3BvaW50KHNpemUgPSAyLAogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSkpICsKICAjZ2VvbV9saW5lKHNpemUgPSAxLjUpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNlYXNvbl9jb2xzKSArCiAgbGFicyh5ID0gIlByb3NvbWUgTGVuZ3RoIFxuUmVzaWR1YWxzIiwKICAgICAgIHggPSAiIikgKwogIHRoZW1lX21hdHRfZmFjZXRzKGJhc2Vfc2l6ZSA9IDE0KQoKI2dnYXJyYW5nZShzYWxfY29tcF9jdG1heF9yZXNpZF9wbG90LCBzYWxfY29tcF9zaXplX3Jlc2lkX3Bsb3QsIG5yb3cgPSAyLCBjb21tb24ubGVnZW5kID0gVCwgbGVnZW5kID0gInJpZ2h0IikKYGBgCgojIyBUcmFpdCBDb3JyZWxhdGlvbnMKClJlZ2FyZGxlc3Mgb2YgdGhlIHVuZGVybHlpbmcgbWVjaGFuaXNtIChnZW5ldGljIGRpZmZlcmVudGlhdGlvbiBvciBwaGVub3R5cGljIHBsYXN0aWNpdHkpLCB3ZSBleHBlY3QgdGhhdCBjb2xsZWN0aW9ucyBmcm9tIHdhcm1lciB3YXRlcnMgc2hvdWxkIHlpZWxkIGNvcGVwb2RzIHdpdGggaGlnaGVyIHRoZXJtYWwgbGltaXRzIGFuZCBzbWFsbGVyIGJvZHkgc2l6ZXMuIE91ciBvYnNlcnZhdGlvbnMgbGFyZ2VseSBmaXQgdGhpcyBleHBlY3RhdGlvbiwgd2l0aCBzdHJvbmcgaW5jcmVhc2VzIGluIENUbWF4IGF0IGhpZ2hlciB0ZW1wZXJhdHVyZXMsIGFuZCBhIGdlbmVyYWwgZGVjcmVhc2UgaW4gcHJvc29tZSBsZW5ndGhzIGFzIHRlbXBlcmF0dXJlIGluY3JlYXNlZC4gCgpgYGB7ciB0ZW1wLWNvcnMsIGZpZy53aWR0aD0xNSwgZmlnLmhlaWdodD02fQpjdG1heF90ZW1wX3Bsb3QgPSBnZ3Bsb3QoZnVsbF9kYXRhLCBhZXMoeCA9IGNvbGxlY3Rpb25fdGVtcCwgeSA9IGN0bWF4KSkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IFQsCiAgICAgICAgICAgICAgbGluZXdpZHRoID0gMiwgCiAgICAgICAgICAgICAgY29sb3VyID0gImdyZXkiKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IHNpdGUpLCAKICAgICAgICAgICAgIHNpemUgPSAyLCBhbHBoYSA9IDAuNykgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNpdGVfY29scykgKyAKICBsYWJzKHkgPSAiQ1RtYXggKMKwQykiLAogICAgICAgeCA9ICJDb2xsZWN0aW9uIFRlbXAuICjCsEMpIikgKwogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnNpemVfdGVtcF9wbG90ID0gZ2dwbG90KGZ1bGxfZGF0YSwgYWVzKHggPSBjb2xsZWN0aW9uX3RlbXAsIHkgPSBzaXplKSkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IFQsCiAgICAgICAgICAgICAgbGluZXdpZHRoID0gMiwgCiAgICAgICAgICAgICAgY29sb3VyID0gImdyZXkiKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IHNpdGUpLCAKICAgICAgICAgICAgIHNpemUgPSAyLCBhbHBoYSA9IDAuNykgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNpdGVfY29scykgKyAKICBsYWJzKHkgPSAiUHJvc29tZSBMZW5ndGggKG1tKSIsCiAgICAgICB4ID0gIkNvbGxlY3Rpb24gVGVtcC4gKMKwQykiKSArCiAgdGhlbWVfbWF0dCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKCnd0X3RlbXBfcGxvdCA9IGdncGxvdChmdWxsX2RhdGEsIGFlcyh4ID0gY29sbGVjdGlvbl90ZW1wLCB5ID0gd2FybWluZ190b2wpKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVCwKICAgICAgICAgICAgICBsaW5ld2lkdGggPSAyLCAKICAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleSIpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gc2l0ZSksIAogICAgICAgICAgICAgc2l6ZSA9IDIsIGFscGhhID0gMC43KSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2l0ZV9jb2xzKSArIAogIGxhYnMoeSA9ICJXYXJtaW5nIFRvbGVyYW5jZSAowrBDKSIsCiAgICAgICB4ID0gIkNvbGxlY3Rpb24gVGVtcC4gKMKwQykiKSArCiAgdGhlbWVfbWF0dCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKCmdnYXJyYW5nZShjdG1heF90ZW1wX3Bsb3QsIHd0X3RlbXBfcGxvdCwgc2l6ZV90ZW1wX3Bsb3QsIGNvbW1vbi5sZWdlbmQgPSBULCBsZWdlbmQgPSAiYm90dG9tIiwgbnJvdyA9IDEpCmBgYAoKU2hvd24gYmVsb3cgYXJlIHRoZXNlIHRlbXBlcmF0dXJlIGNvcnJlbGF0aW9ucyBmb3IgZWFjaCBpbmRpdmlkdWFsIHBvcHVsYXRpb24uIFZhcmlhdGlvbiBpbiB0aGUgdGVtcGVyYXR1cmUgc2Vuc2l0aXZpdHkgb2YgdGhlc2UgdHJhaXRzIGFwcGVhcnMgdG8gdmFyeSBhY3Jvc3MgcG9wdWxhdGlvbnMsIHdpdGggcmVkdWNlZCBzbG9wZXMgaW4gYm90aCB0aGUgbG93ZXN0IGFuZCB0aGUgaGlnaGVzdCBsYXRpdHVkZSBwb3B1bGF0aW9ucy4gQWdhaW4sIHdlIGVtcGhhc2l6ZSB0aGF0IHRoaXMgb2JzZXJ2ZWQgdHJhaXQgdmFyaWF0aW9uIG1heSBzdGVtIGZyb20gZWl0aGVyIChvciBib3RoKSBwbGFzdGljIGFuZCBnZW5ldGljIGVmZmVjdHMuIEhvd2V2ZXIsIHRoZXNlIG9ic2VydmF0aW9ucyBwcm92aWRlIGVzdGltYXRlcyBmb3IgcmVhbGlzdGljIHBhdHRlcm5zIGluIHRlbXBlcmF0dXJlIHNlbnNpdGl2aXR5IGZvciB0aGVzZSBwb3B1bGF0aW9ucy4gCgpgYGB7ciBwb3AtdGVtcC1jb3JzLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQpnZ3Bsb3QoZnVsbF9kYXRhLCBhZXMoeCA9IGNvbGxlY3Rpb25fdGVtcCwgeSA9IGN0bWF4KSkgKyAKICBmYWNldF93cmFwKC5+c2l0ZSkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IFQsCiAgICAgICAgICAgICAgbGluZXdpZHRoID0gMiwgCiAgICAgICAgICAgICAgY29sb3VyID0gImdyZXkiKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IHNpdGUpLCAKICAgICAgICAgICAgIHNpemUgPSAyLCBhbHBoYSA9IDAuNykgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNpdGVfY29scykgKyAKICBsYWJzKHkgPSAiQ1RtYXggKMKwQykiLAogICAgICAgeCA9ICJDb2xsZWN0aW9uIFRlbXAuICjCsEMpIikgKwogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmdncGxvdChmdWxsX2RhdGEsIGFlcyh4ID0gY29sbGVjdGlvbl90ZW1wLCB5ID0gc2l6ZSkpICsgCiAgZmFjZXRfd3JhcCgufnNpdGUpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBULAogICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDIsIAogICAgICAgICAgICAgIGNvbG91ciA9ICJncmV5IikgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBzaXRlKSwgCiAgICAgICAgICAgICBzaXplID0gMiwgYWxwaGEgPSAwLjcpICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiAgbGFicyh5ID0gIlByb3NvbWUgTGVuZ3RoIChtbSkiLAogICAgICAgeCA9ICJDb2xsZWN0aW9uIFRlbXAuICjCsEMpIikgKwogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmBgYAoKT25lIGFkZGl0aW9uYWwgY29ycmVsYXRpb24gb2YgaW50ZXJlc3QgaXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHByb3NvbWUgbGVuZ3RoIGFuZCBDVG1heC4gSW4gbWFueSBjYXNlcywgbGFyZ2VyIGJvZHkgc2l6ZXMgYXJlIGFzc29jaWF0ZWQgd2l0aCBjb2xkIGFkYXB0YXRpb24vYWNjbGltYXRpb24sIGFuZCB0aGVyZSBpcyBhIGdlbmVyYWwgdHJlbmQgb2YgZGVjcmVhc2luZyB0aGVybWFsIGxpbWl0cyB3aXRoIGluY3JlYXNpbmcgc2l6ZS4gU2hvd24gYmVsb3cgaXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHByb3NvbWUgbGVuZ3RoIGFuZCBDVG1heCBpbiBvdXIgZGF0YSBzZXQuIEluZGl2aWR1YWwgcmVncmVzc2lvbiBsaW5lcyBmb3IgZWFjaCBzaXRlIGFyZSBhbHNvIGluY2x1ZGVkIC0gdGhlIGRhcmsgZ3JleSBsaW5lcyBpbiB0aGUgYmFja2dyb3VuZCByZXByZXNlbnQgdGhlICd1bml2ZXJzYWwnIHJlZ3Jlc3Npb24gZm9yIHRoYXQgc2l0ZSwgd2l0aCBpbmRpdmlkdWFsIGNvbG9yZWQgcmVncmVzc2lvbiBsaW5lcyBmb3IgZWFjaCBjb2xsZWN0aW9uLiBBY3Jvc3Mgb3VyIGNvbGxlY3Rpb25zLCB3ZSBzZWUgZXZpZGVuY2UgZm9yIHRoaXMgcmVsYXRpb25zaGlwLCB3aXRoIGxhcmdlciBpbmRpdmlkdWFscyBoYXZpbmcgbG93ZXIgdGhlcm1hbCBsaW1pdHMuICAgICAgCgpgYGB7ciBjdG1heC12cy1zaXplLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0xMH0KdW5pdmVyc2FsX3NpemUgPSBmdWxsX2RhdGEgJT4lIAogIGdncGxvdChhZXMoeCA9IHNpemUsIHkgPSBjdG1heCkpICsgCiAgIyBnZW9tX3Ntb290aChkYXRhID0gZmlsdGVyKGZ1bGxfZGF0YSwgY3RtYXggPiAzMSksIAogICMgICAgICAgICAgICAgYWVzKHggPSBzaXplLCB5ID0gY3RtYXgpLAogICMgICAgICAgICAgICAgbWV0aG9kID0gImxtIiwgCiAgIyAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTYwIiwgCiAgIyAgICAgICAgICAgICBzZSA9IEYsCiAgIyAgICAgICAgICAgICBsaW5ld2lkdGggPSAyKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVCwKICAgICAgICAgICAgICBsaW5ld2lkdGggPSAyLAogICAgICAgICAgICAgIGNvbG91ciA9ICJncmV5NzAiKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IHNpdGUpLAogICAgICAgICAgICAgc2l6ZSA9IDIsIGFscGhhID0gMC43KSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2l0ZV9jb2xzKSArIAogIGxhYnMoeSA9ICJDVG1heCAowrBDKSIsCiAgICAgICB4ID0gIiIpICsKICB0aGVtZV9tYXR0KGJhc2Vfc2l6ZSA9IDE0KSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKQoKcG9wX3NpemUgPSBmdWxsX2RhdGEgJT4lIAogIGdncGxvdChhZXMoeCA9IHNpemUsIHkgPSBjdG1heCwgY29sb3VyID0gc2l0ZSwgZ3JvdXAgPSBzZWFzb24pKSArIAogIGZhY2V0X3dyYXAoc2l0ZX4uKSArIAogICMgZ2VvbV9zbW9vdGgoZGF0YSA9IGZpbHRlcihmdWxsX2RhdGEsIGN0bWF4ID4gMzEpLCAKICAjICAgICAgICAgICAgIGFlcyh4ID0gc2l6ZSwgeSA9IGN0bWF4KSwKICAjICAgICAgICAgICAgIG1ldGhvZCA9ICJsbSIsIAogICMgICAgICAgICAgICAgY29sb3VyID0gImdyZXk2MCIsIAogICMgICAgICAgICAgICAgc2UgPSBGLAogICMgICAgICAgICAgICAgbGluZXdpZHRoID0gMikgKyAKICBnZW9tX3Ntb290aChkYXRhID0gZnVsbF9kYXRhLCAKICAgICAgICAgICAgICBhZXMoeCA9IHNpemUsIHkgPSBjdG1heCwgZ3JvdXAgPSBzaXRlKSwgCiAgICAgICAgICAgICAgY29sb3VyID0gImdyZXkyMCIsIG1ldGhvZCA9ICJsbSIsIHNlID0gRikgKyAKICBnZW9tX3BvaW50KHNpemUgPSAxLjMsIGFscGhhID0gMC4zKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRiwKICAgICAgICAgICAgICBsaW5ld2lkdGggPSAxKSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2l0ZV9jb2xzKSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBjKDAuNiwgMC44LCAxKSkgKyAKICBsYWJzKHkgPSAiQ1RtYXggKMKwQykiLAogICAgICAgeCA9ICJQcm9zb21lIExlbmd0aCAobW0pIikgKwogIHRoZW1lX21hdHQoYmFzZV9zaXplID0gMTQpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKCmdnYXJyYW5nZSh1bml2ZXJzYWxfc2l6ZSwgcG9wX3NpemUsIGNvbW1vbi5sZWdlbmQgPSBULCBsZWdlbmQgPSAibm9uZSIsIG5yb3cgPSAyKQpgYGAKClRoaXMgcmVsYXRpb25zaGlwIG1heSBiZSBhZmZlY3RlZCBieSBjaGFuZ2VzIGluIHRlbXBlcmF0dXJlIGF0IGVhY2ggc2l0ZSwgaG93ZXZlciwgd2hpY2ggbWF5IGFmZmVjdCBib3RoIGJvZHkgc2l6ZSBhbmQgdGhlcm1hbCBsaW1pdHMuIElmIHRoZXJlIGlzIGEgdHJ1ZSBtZWNoYW5pc3RpYyByZWxhdGlvbnNoaXAgYmV0d2VlbiBib2R5IHNpemUgYW5kIHRoZXJtYWwgbGltaXRzLCB3ZSB3b3VsZCBleHBlY3QgdG8gc2VlIHRoaXMgcmVsYXRpb25zaGlwIGVtZXJnZSAqKndpdGhpbioqIHBvcHVsYXRpb25zIG9yIGV2ZW4gaW5kaXZpZHVhbCBjb2xsZWN0aW9ucy4gU2hvd24gYmVsb3cgaXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIENUbWF4IGFuZCBzaXplIHJlc2lkdWFscywgYWNxdWlyZWQgZnJvbSByZWdyZXNzaW9ucyBvZiB0aGVzZSB0cmFpdHMgYWdhaW5zdCBjb2xsZWN0aW9uIHRlbXBlcmF0dXJlLiBUaGlzIHN1YnN0YW50aWFsbHkgcmVkdWNlcyB0aGUgc3RyZW5ndGggb2YgdGhlIGFwcGFyZW50IHJlbGF0aW9uc2hpcCwgYnV0IHRoZXJlIGlzIHN0aWxsIGEgc2xpZ2h0bHkgbmVnYXRpdmUgb3ZlcmFsbCByZWxhdGlvbnNoaXAsIHNwYW5uaW5nIGJvdGggYWNyb3NzLXBvcHVsYXRpb24sIHdpdGhpbi1wb3B1bGF0aW9uLCBhbmQgZXZlbiB3aXRoaW4tY29sbGVjdGlvbiBzY2FsZXMgKHNlZSB0aGUgU2F3eWVyIFBhcmsgY29sbGVjdGlvbnMsIGZvciBleGFtcGxlKS4gICAgIAoKYGBge3IgY3RtYXgtdnMtc2l6ZS1yZXNpZHMsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTEwfQpmaWx0ZXJlZF9kYXRhID0gZnVsbF9kYXRhICU+JSAKICBkcm9wX25hKHNpemUsIGN0bWF4KSAlPiUgCiAgbXV0YXRlKHRlbXBfY2VudCA9IHNjYWxlKGNvbGxlY3Rpb25fdGVtcCwgc2NhbGUgPSBGKSwKICAgICAgICAgc2FsX2NlbnQgPSBzY2FsZShjb2xsZWN0aW9uX3NhbGluaXR5LCBzY2FsZSA9IEYpLAogICAgICAgICBzYWxfdHlwZSA9IGlmX2Vsc2UoY29sbGVjdGlvbl9zYWxpbml0eSA+IDIwLCAiSGlnaCIsICJMb3ciKSkKCmN0bWF4X3RlbXAubW9kZWwgPSBsbShjdG1heCB+IGNvbGxlY3Rpb25fdGVtcCArIHNpdGUsIGRhdGEgPSBmaWx0ZXJlZF9kYXRhKQpjdG1heF9yZXNpZHMgPSByZXNpZHVhbHMoY3RtYXhfdGVtcC5tb2RlbCkKCnNpemVfdGVtcC5tb2RlbCA9IGxtKHNpemUgfiBjb2xsZWN0aW9uX3RlbXAgKyBzaXRlLCBkYXRhID0gZmlsdGVyZWRfZGF0YSkKc2l6ZV9yZXNpZHMgPSByZXNpZHVhbHMoc2l6ZV90ZW1wLm1vZGVsKQoKdW5pdmVyc2FsX3Jlc2lkcyA9IGZpbHRlcmVkX2RhdGEgJT4lIAogIG11dGF0ZShjdG1heF9yZXNpZHMgPSBjdG1heF9yZXNpZHMsCiAgICAgICAgIHNpemVfcmVzaWRzID0gc2l6ZV9yZXNpZHMpIAoKYWxsX3Jlc2lkcyA9IGdncGxvdCh1bml2ZXJzYWxfcmVzaWRzLCBhZXMoeCA9IHNpemVfcmVzaWRzLCB5ID0gY3RtYXhfcmVzaWRzKSkgKyAKICAjIGdlb21fc21vb3RoKGRhdGEgPSBmaWx0ZXIoZnVsbF9kYXRhLCBjdG1heCA+IDMxKSwgCiAgIyAgICAgICAgICAgICBhZXMoeCA9IHNpemUsIHkgPSBjdG1heCksCiAgIyAgICAgICAgICAgICBtZXRob2QgPSAibG0iLCAKICAjICAgICAgICAgICAgIGNvbG91ciA9ICJncmV5NjAiLCAKICAjICAgICAgICAgICAgIHNlID0gRiwKICAjICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDIpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBULAogICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDIsCiAgICAgICAgICAgICAgY29sb3VyID0gImdyZXk3MCIpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gc2l0ZSksCiAgICAgICAgICAgICBzaXplID0gMiwgYWxwaGEgPSAwLjcpICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiAgbGFicyh5ID0gIkNUbWF4IFJlc2lkdWFscyIsCiAgICAgICB4ID0gIiIpICsKICB0aGVtZV9tYXR0KGJhc2Vfc2l6ZSA9IDE0KSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKQoKcG9wX3Jlc2lkcyA9IGdncGxvdCh1bml2ZXJzYWxfcmVzaWRzLCBhZXMoeCA9IHNpemVfcmVzaWRzLCB5ID0gY3RtYXhfcmVzaWRzLCBjb2xvdXIgPSBzaXRlLCBncm91cCA9IHNlYXNvbikpICsgCiAgZmFjZXRfd3JhcChzaXRlfi4pICsgCiAgIyBnZW9tX3Ntb290aChkYXRhID0gZmlsdGVyKGZ1bGxfZGF0YSwgY3RtYXggPiAzMSksIAogICMgICAgICAgICAgICAgYWVzKHggPSBzaXplLCB5ID0gY3RtYXgpLAogICMgICAgICAgICAgICAgbWV0aG9kID0gImxtIiwgCiAgIyAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTYwIiwgCiAgIyAgICAgICAgICAgICBzZSA9IEYsCiAgIyAgICAgICAgICAgICBsaW5ld2lkdGggPSAyKSArIAogIGdlb21fc21vb3RoKGFlcyh4ID0gc2l6ZV9yZXNpZHMsIHkgPSBjdG1heF9yZXNpZHMsIGdyb3VwID0gc2l0ZSksIAogICAgICAgICAgICAgIGNvbG91ciA9ICJncmV5MjAiLCBtZXRob2QgPSAibG0iLCBzZSA9IEYpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMS4zLCBhbHBoYSA9IDAuMykgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEYsCiAgICAgICAgICAgICAgbGluZXdpZHRoID0gMSkgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNpdGVfY29scykgKyAKICBsYWJzKHkgPSAiQ1RtYXggUmVzaWR1YWxzIiwKICAgICAgIHggPSAiUHJvc29tZSBMZW5ndGggUmVzaWR1YWxzIikgKwogIHRoZW1lX21hdHQoYmFzZV9zaXplID0gMTQpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKCmdnYXJyYW5nZShhbGxfcmVzaWRzLCBwb3BfcmVzaWRzLCBjb21tb24ubGVnZW5kID0gVCwgbGVnZW5kID0gIm5vbmUiLCBucm93ID0gMikKYGBgCgpgYGB7ciBjdG1heC1tb2RlbCwgaW5jbHVkZSA9IEZ9CiMgCiMgZnVsbC5tb2RlbCA9IGxtKGRhdGEgPSBmaWx0ZXJlZF9kYXRhLCAKIyAgICAgICAgICAgICAgICAgY3RtYXggfiBzaXRlICogY29sbGVjdGlvbl90ZW1wICogc2l6ZSwgCiMgICAgICAgICAgICAgICAgICAgIG5hLmFjdGlvbiA9ICJuYS5mYWlsIikKIyAKIyBkcmVkZ2VfcmVzdWx0cyA9IE11TUluOjpkcmVkZ2UoZnVsbC5tb2RlbCkKIyB0b3BfbW9kZWwgPSBNdU1Jbjo6Z2V0Lm1vZGVscyhkcmVkZ2VfcmVzdWx0cywgMSlbWzFdXSAjQmVzdCBtb2RlbAojIAojIHRlbXBfdmFscyA9IGFzX3RpYmJsZShlbXRyZW5kcyh0b3BfbW9kZWwsIHNwZWMgPSAic2l0ZSIsIHZhciA9ICJjb2xsZWN0aW9uX3RlbXAiKSkgCiMgc2l6ZV92YWxzID0gYXNfdGliYmxlKGVtdHJlbmRzKHRvcF9tb2RlbCwgc3BlYyA9ICJzaXRlIiwgdmFyID0gInNpemUiKSkgCgpjdG1heC5tb2RlbCA9IGxtZTQ6OmxtZXIoCiAgZGF0YSA9IGZpbHRlcmVkX2RhdGEsIAogIGN0bWF4IH4gdGVtcF9jZW50ICsgc2l6ZSArIHNhbF90eXBlICsgKDEgKyB0ZW1wX2NlbnR8c2l0ZSkpCmBgYAoKVG8gbW9yZSBmb3JtYWxseSB0ZXN0IHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gQ1RtYXgsIGNvbGxlY3Rpb24gdGVtcGVyYXR1cmUsIGFuZCBzaXplLCB3ZSB1c2VkIGEgbGluZWFyIG1peGVkIGVmZmVjdHMgbW9kZWwsIHN0cnVjdHVyZWQgYXMgYGN0bWF4IH4gY29sbGVjdGlvbl90ZW1wICsgc2l6ZSArIHNhbGluaXR5X3R5cGUgKyAoMXxzaXRlKWAuIFRoaXMgZXhhbWluZXMgdGhlIGVmZmVjdHMgb2YgdGVtcGVyYXR1cmUgYW5kIHNpemUgb24gQ1RtYXgsIGFsb25nIHdpdGggZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgc2FsaW5pdHkgZ3JvdXBpbmdzLiBDb2xsZWN0aW9uIHRlbXBlcmF0dXJlIHdhcyBjZW50ZXJlZCBhbmQgc2FsaW5pdHkgdHlwZSBhc3NpZ25lZCAoImxvdyIgc2FsaW5pdHkgYXMgYW55dGhpbmcgYmVsb3cgMjAgcHN1LCAiaGlnaCIgc2FsaW5pdHkgYXMgYW55dGhpbmcgYWJvdmUgMjAgcHN1KSBiZWZvcmUgbW9kZWwgZml0dGluZy4gVGhlIG1vZGVsIGFsc28gaW5jbHVkZXMgcmFuZG9tIGludGVyY2VwdHMgZm9yIGVhY2ggc2l0ZSBhbmQgcmFuZG9tIHNsb3BlcyBmb3IgY29sbGVjdGlvbiB0ZW1wZXJhdHVyZSAoaS5lLiAtIHZhcmlhdGlvbiBpbiB0aGUgYWNjbGltYXRpb24gY2FwYWNpdHkgb2YgQ1RtYXgpLiAKCkNvbGxlY3Rpb24gdGVtcGVyYXR1cmUgYW5kIGJvZHkgc2l6ZSBib3RoIGhhZCBhIHNpZ25pZmljYW50IGVmZmVjdCBvbiBDVG1heCwgYnV0IHNhbGluaXR5IHR5cGUgZGlkIG5vdC4gVGhlIG92ZXJhbGwgZWZmZWN0IG9mIHRlbXBlcmF0dXJlIHN1Z2dlc3RzIGFuIGluY3JlYXNlIGluIENUbWF4IG9mIGByIHJvdW5kKHVubmFtZShmaXhlZihjdG1heC5tb2RlbClbInRlbXBfY2VudCJdKSwgZGlnaXRzID0gMilgwrBDIHBlciDCsEMgaW5jcmVhc2UgaW4gY29sbGVjdGlvbiB0ZW1wZXJhdHVyZSAoaS5lLiAtIGFuIEFSUiB2YWx1ZSBvZiBgciByb3VuZCh1bm5hbWUoZml4ZWYoY3RtYXgubW9kZWwpWyJ0ZW1wX2NlbnQiXSksIGRpZ2l0cyA9IDIpYCksIHdoaWxlIGluY3JlYXNpbmcgYm9keSBzaXplcyBkZWNyZWFzZSBDVG1heCBieSBgciByb3VuZCh1bm5hbWUoZml4ZWYoY3RtYXgubW9kZWwpWyJzaXplIl0pLCBkaWdpdHMgPSAyKWDCsEMgcGVyIG1tIChvciBhIGRlY3JlYXNlIG9mIH5gciByb3VuZCh1bm5hbWUoZml4ZWYoY3RtYXgubW9kZWwpWyJzaXplIl0pLCBkaWdpdHMgPSAyKS8xMGDCsEMgcGVyIHRlbnRoIG9mIGEgbW0sIHdoaWNoIGlzIG1vcmUgYmlvbG9naWNhbGx5IHJlYWxpc3RpYyBmb3IgKkEuIHRvbnNhKikuIFdoaWxlIG5vdCBzaWduaWZpY2FudCwgdGhlIG1vZGVsIHN1Z2dlc3RzIGxvdyBzYWxpbml0eSBzaXRlcyBoYWQgbG93ZXIgdGhlcm1hbCBsaW1pdHMgYnkgfmByIGFicyhyb3VuZCh1bm5hbWUoZml4ZWYoY3RtYXgubW9kZWwpWyJzYWxfdHlwZUxvdyJdKSwgZGlnaXRzID0gMSkpYMKwQy4KCmBgYHtyfQoKI3N1bW1hcnkoY3RtYXgubW9kZWwpCgplZmZlY3RzX3N1bW1hcnkgPSBkYXRhLmZyYW1lKAogICJUZW1wZXJhdHVyZSIgPSB1bm5hbWUoZml4ZWYoY3RtYXgubW9kZWwpWyJ0ZW1wX2NlbnQiXSksCiAgIlNpemUiID0gdW5uYW1lKGZpeGVmKGN0bWF4Lm1vZGVsKVsic2l6ZSJdKSwKICAiU2FsaW5pdHkiID0gdW5uYW1lKGZpeGVmKGN0bWF4Lm1vZGVsKVsic2FsX3R5cGVMb3ciXSkpCgprbml0cjo6a2FibGUoZWZmZWN0c19zdW1tYXJ5KQpgYGAKCkJ5IGV4dHJhY3RpbmcgdGhlIGNvbmRpdGlvbmFsIG1vZGUgZm9yIHRoZSByYW5kb20gZWZmZWN0cywgd2UgY2FuIGFsc28gZXhhbWluZSBob3cgdGhlcm1hbCBsaW1pdHMgdmFyeSBhY3Jvc3Mgc2l0ZXMgYmV5b25kIHRoZSBpbmZsdWVuY2Ugb2YgY29sbGVjdGlvbiB0ZW1wZXJhdHVyZXMgYW5kIGJvZHkgc2l6ZXMuIFNob3duIGJlbG93IGFyZSB0aGVzZSB2YWx1ZXMsIGV4dHJhY3RlZCBmcm9tIHRoZSBsaW5lYXIgbWl4ZWQgZWZmZWN0cyBtb2RlbC4gV2UgY2FuIHNlZSB0aGF0LCBzaW1pbGFyIHRvIHdoYXQncyBiZWVuIG9ic2VydmVkIGluIGNvbW1vbiBnYXJkZW4gZXhwZXJpbWVudHMgd2l0aCAqQS4gdG9uc2EqIHByZXZpb3VzbHksIHNpZ25pZmljYW50IGRpdmVyZ2VuY2VzIGFyZSBwcmVzZW50IGF0IG9ubHkgYSBmZXcgc2l0ZXMsIHdpdGggRm9ydCBIYW1lciBhbmQgUml0Y2hpZSBXaGFyZiBoYXZpbmcgaW5jcmVhc2VkIGFuZCBkZWNyZWFzZWQgdGhlcm1hbCBsaW1pdHMgcmVzcGVjdGl2ZWx5LiBJbnRlcmVzdGluZ2x5LCBib3RoIG9mIHRoZXNlIHNpdGVzIHdlcmUgbG93IHNhbGluaXR5IHNpdGVzLCBhbHNvIGluIGxpbmUgd2l0aCBwcmV2aW91cyByZXN1bHRzIHN1Z2dlc3RpbmcgZ2VuZSBmbG93IGJldHdlZW4gaGlnaCBzYWxpbml0eSBzaXRlcyBtYXkgY29uc3RyYWluIGRpZmZlcmVudGlhdGlvbi4gCgpgYGB7ciBwb3AtZWZmcy1wbG90LCBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD02fQpwb3BfZWZmcyA9IFJFc2ltKGN0bWF4Lm1vZGVsKSAlPiUgCiAgZHBseXI6OnNlbGVjdCgic2l0ZSIgPSBncm91cElELCB0ZXJtLCBtZWFuLCBzZCkgJT4lIAogIGZpbHRlcih0ZXJtID09ICIoSW50ZXJjZXB0KSIpICU+JSAKICBpbm5lcl9qb2luKHNpdGVfZGF0YSwgYnkgPSBjKCJzaXRlIikpICU+JSAKICBtdXRhdGUoc2l0ZSA9IGZjdF9yZW9yZGVyKHNpdGUsIGxhdCkpCgojcGxvdFJFc2ltKFJFc2ltKGN0bWF4Lm1vZGVsKSkgICMgcGxvdCB0aGUgaW50ZXJ2YWwgZXN0aW1hdGVzCgpnZ3Bsb3QocG9wX2VmZnMsIGFlcyh4ID0gbGF0LCB5ID0gbWVhbiwgY29sb3VyID0gc2l0ZSkpICsgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBtZWFuIC0gMS45NiAqIHNkLCB5bWF4ID0gbWVhbiArIDEuOTYgKiBzZCksCiAgICAgICAgICAgICAgICB3aWR0aCA9IDAuNSwgbGluZXdpZHRoID0gMSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAzKSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2l0ZV9jb2xzKSArIAogIGxhYnMoeCA9ICJMYXRpdHVkZSIsIAogICAgICAgeSA9ICJQb3B1bGF0aW9uIEVmZmVjdCIpICsgCiAgdGhlbWVfbWF0dCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKYGBgCgpGaW5hbGx5LCBzaG93biBiZWxvdyBhcmUgdGhlIGVzdGltYXRlZCByYW5kb20gc2xvcGVzIGZvciBlYWNoIHNpdGUuIFRoZXNlIHJlcHJlc2VudCB0aGUgZWZmZWN0cyBvZiBjb2xsZWN0aW9uIHRlbXBlcmF0dXJlIG9uIENUbWF4IGZvciBlYWNoIHNpdGUuIEludGVyZXN0aW5nbHksIHRoZXNlIGVzdGltYXRlcyBkaXZlcmdlIGZyb20gdGhlIHJlc3VsdHMgb2YgcHJldmlvdXMgY29tbW9uIGdhcmRlbiBleHBlcmltZW50cywgd2hpY2ggc2hvd2VkIHRoZSBzdHJvbmdlc3QgcGxhc3RpY2l0eSBpbiBoaWdoIGxhdGl0dWRlIHNpdGVzLiBIZXJlLCBhY2NsaW1hdGlvbiBhcHBlYXJzIHRvIHBlYWsgaW4gbWlkLWxhdGl0dWRlcywgYW5kIGRlY3JlYXNlIGF0IGJvdGggaGlnaCBhbmQgbG93IGxhdGl0dWRlIHNpdGVzLiAKCmBgYHtyIHNpdGUtYXJyLXBsb3QsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTR9CmNvZWZmaWNpZW50cyhjdG1heC5tb2RlbCkkc2l0ZSAlPiUKICBqYW5pdG9yOjpjbGVhbl9uYW1lcygpICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAic2l0ZSIpICU+JQogIGlubmVyX2pvaW4oc2l0ZV9kYXRhKSAlPiUgCiAgbXV0YXRlKHNpdGUgPSBmY3RfcmVvcmRlcihzaXRlLCBsYXQpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gdGVtcF9jZW50LCB5ID0gc2l0ZSkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBzaXRlKSwKICAgICAgICAgICAgIHNpemUgPSA1KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsKICBsYWJzKHggPSAiQVJSIikgKyAKICB0aGVtZV9tYXR0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKIyMgVHJhaXQgVmFyaWFiaWxpdHkKClNob3duIGJlbG93IGlzIHRoZSB0cmFpdCB2YXJpYXRpb24gKHJhbmdlcykgZm9yIGVhY2ggc2l0ZS4gUmFuZ2VzIGFyZSBjYWxjdWxhdGVkIGZvciBlYWNoIGNvbGxlY3Rpb24gc2VwYXJhdGVseS4gCgpgYGB7ciB0cmFpdC1yYW5nZS1wbG90LCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NC41fQp0cmFpdF9yYW5nZXMgPSBmdWxsX2RhdGEgJT4lIAogIGdyb3VwX2J5KHNpdGUsIHNlYXNvbiwgY29sbGVjdGlvbl90ZW1wLCBjb2xsZWN0aW9uX3NhbGluaXR5LCBkb3ksIGxhdCkgJT4lIAogIHN1bW1hcmlzZShtZWFuX2N0bWF4ID0gbWVhbihjdG1heCksCiAgICAgICAgICAgIGN0bWF4X3JhbmdlID0gbWF4KGN0bWF4KSAtIG1pbihjdG1heCksCiAgICAgICAgICAgIGN0bWF4X3ZhciA9IHZhcihjdG1heCksCiAgICAgICAgICAgIG1lYW5fc2l6ZSA9IG1lYW4oc2l6ZSksCiAgICAgICAgICAgIHNpemVfcmFuZ2UgPSBtYXgoc2l6ZSkgLSBtaW4oc2l6ZSksCiAgICAgICAgICAgIHNpemVfdmFyID0gdmFyKHNpemUpKSAlPiUgCiAgbXV0YXRlKHByb3BfY3RtYXhfcmFuZ2UgPSBjdG1heF9yYW5nZSAvIG1lYW5fY3RtYXgsCiAgICAgICAgIHByb3Bfc2l6ZV9yYW5nZSA9IHNpemVfcmFuZ2UgLyBtZWFuX3NpemUpCgpjdG1heF9yYW5nZV90ZW1wID0gZ2dwbG90KHRyYWl0X3JhbmdlcywgYWVzKHggPSBjb2xsZWN0aW9uX3RlbXAsIHkgPSBjdG1heF9yYW5nZSwgY29sb3VyID0gc2l0ZSkpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMykgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNpdGVfY29scykgKyAKICBsYWJzKHkgPSAiQ1RtYXggUmFuZ2UgKMKwQykiLAogICAgICAgeCA9ICJDb2xsZWN0aW9uIFRlbXAuICjCsEMpIikgKwogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCgpjdG1heF92YXJfdGVtcCA9IGdncGxvdCh0cmFpdF9yYW5nZXMsIGFlcyh4ID0gY29sbGVjdGlvbl90ZW1wLCB5ID0gY3RtYXhfdmFyLCBjb2xvdXIgPSBzaXRlKSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAzKSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2l0ZV9jb2xzKSArIAogIGxhYnMoeSA9ICJDVG1heCBSYW5nZSAowrBDKSIsCiAgICAgICB4ID0gIkNvbGxlY3Rpb24gVGVtcC4gKMKwQykiKSArCiAgdGhlbWVfbWF0dCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKCnNpemVfcmFuZ2VfdGVtcCA9IGdncGxvdCh0cmFpdF9yYW5nZXMsIGFlcyh4ID0gY29sbGVjdGlvbl90ZW1wLCB5ID0gc2l6ZV9yYW5nZSwgY29sb3VyID0gc2l0ZSkpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMykgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNpdGVfY29scykgKyAKICBsYWJzKHkgPSAiU2l6ZSBSYW5nZSAobW0pIiwKICAgICAgIHggPSAiQ29sbGVjdGlvbiBUZW1wLiAowrBDKSIpICsKICB0aGVtZV9tYXR0KCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQoKc2l6ZV92YXJfdGVtcCA9IGdncGxvdCh0cmFpdF9yYW5nZXMsIGFlcyh4ID0gY29sbGVjdGlvbl90ZW1wLCB5ID0gc2l6ZV92YXIsIGNvbG91ciA9IHNpdGUpKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiAgbGFicyh5ID0gIlNpemUgUmFuZ2UgKG1tKSIsCiAgICAgICB4ID0gIkNvbGxlY3Rpb24gVGVtcC4gKMKwQykiKSArCiAgdGhlbWVfbWF0dCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKCmdnYXJyYW5nZShjdG1heF9yYW5nZV90ZW1wLCBzaXplX3JhbmdlX3RlbXAsIGNvbW1vbi5sZWdlbmQgPSBULCBsZWdlbmQgPSAicmlnaHQiKQpgYGAKCkNoYW5nZXMgaW4gdHJhaXQgdmFyaWFuY2UgbWF5IGJlIGluZGljYXRpdmUgb2YgcGhlbm90eXBpYyBzZWxlY3Rpb24uIElmIHNlbGVjdGlvbiAoYXMgb3Bwb3NlZCB0byBhY2NsaW1hdGlvbikgYXJlIGRyaXZpbmcgc2Vhc29uYWwgY2hhbmdlcywgd2UgbWF5IGV4cGVjdCB0byBzZWUgYSByZWR1Y3Rpb24gaW4gdmFyaWFuY2UgaW4gdGhlIHBlYWsgc2FtcGxlcyByZWxhdGl2ZSB0byB0aGUgZWFybHkgc2Vhc29uIHNhbXBsZXMuIE5vdGUgdGhhdCBlYXJseSBzZWFzb24gY29sbGVjdGlvbiB0ZW1wZXJhdHVyZXMgdGhpcyB5ZWFyIHdlcmUgaGlnaGVyIHRoYW4gZXhwZWN0ZWQsIGRyaXZlbiBieSBmYWlybHkgc3Ryb25nIGhlYXR3YXZlcyBhY3Jvc3MgdGhlIE5vcnRoIEF0bGFudGljLiBBcyBzaG93biBpbiB0aGUgdGVtcGVyYXR1cmUgcHJvZmlsZXMgZm9yIGVhY2ggc2l0ZSwgdGhlICdlYXJseScgc2FtcGxlcyB3ZXJlIGNvbGxlY3RlZCBqdXN0IGFmdGVyIGhpZ2ggdGVtcGVyYXR1cmVzIHdlcmUgcmVhY2hlZCwgd2hpbGUgJ3BlYWsnIHNhbXBsZXMgd2VyZSBjb2xsZWN0ZWQgYWZ0ZXIgc2l0ZXMgaGFkIGV4cGVyaWVuY2VkIGhpZ2ggdGVtcGVyYXR1cmVzIGZvciBzZXZlcmFsIHdlZWtzIChnZW5lcmF0aW9ucykuIEFzIHdhcm1pbmcgdG9sZXJhbmNlcyB3ZXJlIGZhaXJseSBoaWdoIHRocm91Z2hvdXQgdGhpcyBwZXJpb2QsIHdlIHdpbGwgYXNzdW1lIHRoYXQgc2VsZWN0aW9uIHdhcyB3ZWFrIGJlZm9yZSB0aGUgZWFybHkgc2FtcGxlcy4gSWYgdGhlIGVhcmx5IG9uc2V0IG9mIGhpZ2ggdGVtcGVyYXR1cmVzIGZpbHRlcmVkIG91dCB2dWxuZXJhYmxlIGdlbm90eXBlcyBwcmlvciB0byBvdXIgc2FtcGxpbmcsIHRoZSByZXN1bHRzIHdpbGwgYmUgYSBjb25zZXJ2YXRpdmUgZXN0aW1hdGUgb2YgdGhlIGVmZmVjdHMgb2Ygc2VsZWN0aW9uIG9uIHRyYWl0IHZhcmlhbmNlLiAgICAgCgpTaG93biBiZWxvdyBpcyB0aGUgc2Vhc29uYWwgcHJvZ3Jlc3Npb24gb2YgdmFyaWFuY2UgaW4gQ1RtYXggZm9yIGVhY2ggc2l0ZS4gRm9yIG1hbnkgc2l0ZXMsIHZhcmlhbmNlIGRlY3JlYXNlZCBiZXR3ZWVuIHRoZSBlYXJseSBhbmQgcGVhayBzYW1wbGVzLCBhbmQgdGhlbiBpbmNyZWFzZWQgYWdhaW4gaW4gdGhlIGxhdGUgc2FtcGxlLiBGb3Igc29tZSBzaXRlcyAoZS5nLiBFc2tlciBQb2ludCksIHRoaXMgaW5jcmVhc2UgaW4gdGhlIGxhdGUgc2FtcGxlIHdhcyBzdWJzdGFudGlhbC4gCgpgYGB7ciBzZWFzb24tdmFyfQpnZ3Bsb3QodHJhaXRfcmFuZ2VzLCBhZXMoeCA9IHNlYXNvbiwgeSA9IGN0bWF4X3ZhciwgY29sb3VyID0gc2l0ZSkpICsgCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IHNpdGUpLCAKICAgICAgICAgICAgbGluZXdpZHRoID0gMS41KSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiAgbGFicyh5ID0gIkNUbWF4IFZhcmlhbmNlIiwKICAgICAgIHggPSAiU2Vhc29uIikgKwogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIAogICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAuMTI1KQpgYGAKClNob3duIGJlbG93IGlzIHRoZSBzZWFzb25hbCBwcm9ncmVzc2lvbiBvZiB2YXJpYW5jZSBpbiBib2R5IHNpemUuIEEgc2ltaWxhciBwYXR0ZXJuIG9mIGRlY3JlYXNpbmcgdmFyaWFuY2UgaW4gcGVhayBzYW1wbGVzIHJlbGF0aXZlIHRvIGVhcmx5IGFuZCBsYXRlIHNhbXBsZXMgaXMgYWdhaW4gc2VlbiBmb3IgbWFueSBzaXRlcy4gVGhlIG9idmlvdXMgZXhjZXB0aW9uIGlzIHRoZSBFc2tlciBQb2ludCBzYW1wbGUsIHdoaWNoIHNhdyB0aGUgb3Bwb3NpdGUgdHJlbmQuIAoKYGBge3J9CmdncGxvdCh0cmFpdF9yYW5nZXMsIGFlcyh4ID0gc2Vhc29uLCB5ID0gc2l6ZV92YXIsIGNvbG91ciA9IHNpdGUpKSArIAogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBzaXRlKSwgCiAgICAgICAgICAgIGxpbmV3aWR0aCA9IDEuNSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAzKSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2l0ZV9jb2xzKSArIAogIGxhYnMoeSA9ICJDVG1heCBWYXJpYW5jZSIsCiAgICAgICB4ID0gIlNlYXNvbiIpICsKICB0aGVtZV9tYXR0KCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCAKICAgICAgICBsZWdlbmQudGl0bGUuYWxpZ24gPSAwLjEyNSkKYGBgCgpTaG93biBiZWxvdyBhcmUgdGhlIHNlYXNvbmFsIGNoYW5nZXMgaW4gdHJhaXQgdmFyaWFuY2UgZm9yIGVhY2ggc2l0ZSBpbmRpdmlkdWFsbHkuIAoKYGBge3IgdmFyLWluZC1wb3BzLXNlYXNvbiwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KZ2dwbG90KHRyYWl0X3JhbmdlcywgYWVzKHggPSBzZWFzb24sIHkgPSBjdG1heF92YXIsIGNvbG91ciA9IHNpdGUpKSArIAogIGZhY2V0X3dyYXAoc2l0ZX4uKSArIAogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBzaXRlKSwgCiAgICAgICAgICAgIGxpbmV3aWR0aCA9IDEuNSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAzKSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2l0ZV9jb2xzKSArIAogIGxhYnMoeSA9ICJDVG1heCBWYXJpYW5jZSIsCiAgICAgICB4ID0gIlNlYXNvbiIpICsKICB0aGVtZV9tYXR0KCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIAogICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAuMTI1KQoKZ2dwbG90KHRyYWl0X3JhbmdlcywgYWVzKHggPSBzZWFzb24sIHkgPSBzaXplX3ZhciwgY29sb3VyID0gc2l0ZSkpICsgCiAgZmFjZXRfd3JhcChzaXRlfi4pICsgCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IHNpdGUpLCAKICAgICAgICAgICAgbGluZXdpZHRoID0gMS41KSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiAgbGFicyh5ID0gIkNUbWF4IFZhcmlhbmNlIiwKICAgICAgIHggPSAiU2Vhc29uIikgKwogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgCiAgICAgICAgbGVnZW5kLnRpdGxlLmFsaWduID0gMC4xMjUpCmBgYAoKYGBge3IgdmFyLWNoYW5nZS10ZW1wLWNoYW5nZSwgaW5jbHVkZSA9IEZ9CnZhcl9jaGFuZ2VfZGF0YSA9IHRyYWl0X3JhbmdlcyAlPiUgIAogIHVuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKG1lYW5fd3QgPSBtZWFuX2N0bWF4IC0gY29sbGVjdGlvbl90ZW1wKSAlPiUgCiAgZ3JvdXBfYnkoc2l0ZSkgJT4lIAogIGFycmFuZ2Uoc2l0ZSwgZG95KSAlPiUgIAogIG11dGF0ZSh0ZW1wX2NoYW5nZSA9IGNvbGxlY3Rpb25fdGVtcCAtIGxhZyhjb2xsZWN0aW9uX3RlbXApLAogICAgICAgICBjdG1heF9jaGFuZ2UgPSBtZWFuX2N0bWF4IC0gbGFnKG1lYW5fY3RtYXgpLAogICAgICAgICB3dF9jaGFuZ2UgPSBtZWFuX3d0IC0gbGFnKG1lYW5fd3QpLAogICAgICAgICB2YXJfY2hhbmdlID0gY3RtYXhfdmFyIC0gbGFnKGN0bWF4X3ZhcikpICU+JSAgCiAgc2VsZWN0KHNpdGUsIHNlYXNvbiwgZG95LCBsYXQsIHRlbXBfY2hhbmdlLCB2YXJfY2hhbmdlLCBjdG1heF9jaGFuZ2UsIHd0X2NoYW5nZSkKCmdncGxvdCh2YXJfY2hhbmdlX2RhdGEsIGFlcyh4ID0gdGVtcF9jaGFuZ2UsIHkgPSB2YXJfY2hhbmdlKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBzaXRlKSwKICAgICAgICAgICAgIHNpemUgPSAzKSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2l0ZV9jb2xzKSArIAogIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSBDaGFuZ2UgKMKwQykiLAogICAgICAgeSA9ICJDaGFuZ2UgaW4gQ1RtYXggVmFyaWFuY2UiKSArIAogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIAogICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAuMTI1KQoKdmFyX2NoYW5nZV9kYXRhICU+JSAKICBtdXRhdGUoc2FtcGxlX2FyciA9IGN0bWF4X2NoYW5nZS90ZW1wX2NoYW5nZSkgJT4lIAogIHNlbGVjdChzaXRlLCBzZWFzb24sIHRlbXBfY2hhbmdlLCBzYW1wbGVfYXJyKSAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB0ZW1wX2NoYW5nZSwgeSA9IHNhbXBsZV9hcnIpKSArIAogIGdlb21fcG9pbnQoKQoKdmFyX2NoYW5nZV9kYXRhICU+JSAKICBtdXRhdGUoc2FtcGxlX2FyciA9IGN0bWF4X2NoYW5nZS90ZW1wX2NoYW5nZSkgJT4lIAogIHNlbGVjdChzaXRlLCBzZWFzb24sIHRlbXBfY2hhbmdlLCBzYW1wbGVfYXJyKSAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBzYW1wbGVfYXJyKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuMSkKCmBgYAoKIyMgQ29tcGFyaW5nIHJhdGVzIG9mIGNoYW5nZQpCb3RoIENUbWF4IGFuZCBib2R5IHNpemUgdmFyaWVkIGJldHdlZW4gc2l0ZXMgYW5kIGFjcm9zcyBzZWFzb25zLiBJdCBjYW4gYmUgZGlmZmljdWx0IHRvIGRpcmVjdGx5IGNvbXBhcmUgdGhlc2UgdHdvIHRyYWl0cy4gV2UgdGFrZSB0d28gYXBwcm9hY2hlcyB0byBlYXNlIHRoaXMgY29tcGFyaXNvbi4gClNob3duIGJlbG93IGlzIGEgY29tcGFyaXNvbiBvZiB0aGUgc2xvcGVzIGZyb20gdGhlIHRyYWl0IHJlZ3Jlc3Npb25zIGFnYWluc3QgY29sbGVjdGlvbiB0ZW1wZXJhdHVyZSBmb3IgZWFjaCBwb3B1bGF0aW9uLCBzdGFuZGFyZGl6ZWQgYnkgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgdHJhaXQgZm9yIGVhY2ggcG9wdWxhdGlvbiAoYWNyb3NzIGFsbCBjb2xsZWN0aW9ucykuIFRoaXMgcHJlc2VudHMgY2hhbmdlIHBlciBkZWdyZWUgY2hhbmdlIGluIGNvbGxlY3Rpb24gdGVtcGVyYXR1cmUgaW4gdW5pdHMgb2Ygc3RhbmRhcmQgZGV2aWF0aW9ucyBmb3IgYm90aCBDVG1heCBhbmQgYm9keSBzaXplLgoKYGBge3IgYWRqLXNsb3BlLWNvbXAsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTZ9CmFkal9zbG9wZXMgPSBmdWxsX2RhdGEgJT4lIAogIGdyb3VwX2J5KHNpdGUsIGxhdCkgJT4lIAogIGFycmFuZ2UoZG95KSAlPiUgIAogIGZpbHRlcihzaXRlICE9ICJLZXkgTGFyZ28iKSAlPiUKICBzdW1tYXJpemUoImN0bWF4X3Nsb3BlIiA9IGNvZWYobG0oY3RtYXggfiBjb2xsZWN0aW9uX3RlbXApKVsiY29sbGVjdGlvbl90ZW1wIl0sIAogICAgICAgICAgICAibWVhbl9jdG1heCIgPSBtZWFuKGN0bWF4KSwKICAgICAgICAgICAgImN0bWF4X3NkIiA9IHNkKGN0bWF4KSwKICAgICAgICAgICAgInNpemVfc2xvcGUiID0gY29lZihsbShzaXplIH4gY29sbGVjdGlvbl90ZW1wKSlbImNvbGxlY3Rpb25fdGVtcCJdLCAKICAgICAgICAgICAgIm1lYW5fc2l6ZSIgPSBtZWFuKHNpemUpLAogICAgICAgICAgICAic2l6ZV9zZCIgPSBzZChzaXplKSwgCiAgICAgICAgICAgICJ0ZW1wX3JhbmdlIiA9IG1heChjb2xsZWN0aW9uX3RlbXApIC0gbWluKGNvbGxlY3Rpb25fdGVtcCkpICU+JSAgCiAgZHJvcF9uYSgpICU+JSAKICBtdXRhdGUoYWRqX2N0bWF4X3Nsb3BlID0gY3RtYXhfc2xvcGUgLyBjdG1heF9zZCwKICAgICAgICAgYWRqX3NpemVfc2xvcGUgPSBzaXplX3Nsb3BlIC8gc2l6ZV9zZCkgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gY29udGFpbnMoIl9zbG9wZSIpLCAKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAic2xvcGVfdHlwZSIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJzbG9wZSIpCgojIGdncGxvdChhZGpfc2xvcGVzLCBhZXMoeCA9IGxhdCwgeSA9IHRlbXBfcmFuZ2UpKSArIAojICAgZ2VvbV9wb2ludCgpICsgCiMgICB0aGVtZV9tYXR0KCkKCmdncGxvdChmaWx0ZXIoYWRqX3Nsb3Blcywgc3RyX2RldGVjdChzbG9wZV90eXBlLCAiYWRqXyIpKSwgYWVzKHggPSBzbG9wZV90eXBlLCB5ID0gYWJzKHNsb3BlKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gc2l0ZSwgY29sb3VyID0gc2l0ZSkpICsgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKyAKICBnZW9tX2xpbmUobGluZXdpZHRoID0gMSkgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNpdGVfY29scykgKyAKICBsYWJzKHggPSAiIiwgCiAgICAgICB5ID0gIlNsb3BlIChhYnNvbHV0ZSB2YWx1ZSkiKSArIAogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMDAsIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjUpKQpgYGAKCkhhbGRhbmVzIGFyZSBhIHNpbWlsYXIgdW5pdCwgcmVwcmVzZW50aW5nIGNoYW5nZSBpbiB1bml0cyBvZiBzdGFuZGFyZCBkZXZpYXRpb25zIHBlciBnZW5lcmF0aW9uLiBUaGlzIGNhbiBiZSBhIHVzZWZ1bCBtZXRyaWMgZm9yIGNvbXBhcmluZyBhY3Jvc3MgdHJhaXRzLCBlc3BlY2lhbGx5IGFzIHRoZSBudW1iZXIgb2YgZ2VuZXJhdGlvbnMgY292ZXJlZCBieSBvdXIgc2FtcGxpbmcgcGVyaW9kIGxpa2VseSB2YXJpZXMgYWNyb3NzIHBvcHVsYXRpb25zLiBUaGUgY2FsY3VsYXRpb24gb2YgaGFsZGFuZXMgaXMgdGFrZW4gZnJvbSBIZW5kcnkgYW5kIEtpbm5pc29uICgxOTk5KSwgd2hpY2ggaW4gdHVybiBpcyBiYXNlZCBvbiB3b3JrIGZyb20gR2luZ2VyaWNoICgxOTkzKS4gV2UgZXN0aW1hdGVkIHRoZSBudW1iZXIgb2YgZ2VuZXJhdGlvbnMgcGFzc2VkIGJldHdlZW4gY29sbGVjdGlvbnMgdXNpbmcgdGhlIGVtcGlyaWNhbCByZWxhdGlvbnNoaXAgYmV0d2VlbiB0ZW1wZXJhdHVyZSBhbmQgZGV2ZWxvcG1lbnQgdGltZSBmb3IgKkFjYXJ0aWEgdG9uc2EqIGZyb20gTGVhbmRybyBldCBhbC4gKDIwMDYpLiBGb3IgaW5pdGlhbCBlc3RpbWF0ZXMsIHdlIHVzZWQgYSB0ZW1wZXJhdHVyZSBoYWxmd2F5IGJldHdlZW4gd2hhdCB3YXMgb2JzZXJ2ZWQgZHVyaW5nIGNvbGxlY3Rpb24sIGFsdGhvdWdoIHRoaXMgZXN0aW1hdGUgY2FuIGJlIGltcHJvdmVkIGJ5IHVzaW5nIG5vbi1saW5lYXIgYXZlcmFnaW5nIHRvIGFjY291bnQgZm9yIEplbnplbidzIEluZXF1YWxpdHkgYW5kIHRoZSBlZmZlY3Qgb2YgdGVtcGVyYXR1cmUgdmFyaWF0aW9uIG9uIHJhdGUgZnVuY3Rpb25zLiBDaGFuZ2VzIHdlcmUgZXhhbWluZWQgZm9yIGVhY2ggcGFpciBvZiBjb2xsZWN0aW9ucyAoZWFybHkgdG8gcGVhaywgYW5kIHBlYWsgdG8gbGF0ZSkuICAgIAoKU2hvd24gYmVsb3cgaXMgYSBjb21wYXJpc29uIG9mIHRoZSBlc3RpbWF0ZWQgaGFsZGFuZSB2YWx1ZXMgZm9yIENUbWF4IGFuZCBib2R5IHNpemUsIHNlcGFyYXRlZCBieSBzZWFzb24uIEtlZXAgaW4gbWluZCB0aGF0IHdoaWxlIHRoaXMgbWV0cmljIGFjY291bnRzIGZvciBkaWZmZXJlbmNlcyBpbiB0aGUgbnVtYmVyIG9mIGdlbmVyYXRpb25zIGJldHdlZW4gY29sbGVjdGlvbnMsIGl0IGRvZXMgbm90IGRpcmVjdGx5IGFjY291bnQgZm9yIGRpZmZlcmVuY2VzIGluIHRlbXBlcmF0dXJlLCBsZWFkaW5nIHRvIGluZmxhdGVkIHZhbHVlcyBpbiB0aGUgInBlYWsgdG8gbGF0ZSIgY29tcGFyaXNvbnMsIHdoaWNoIHR5cGljYWxseSBjb3ZlcmVkIGEgbGFyZ2VyIHJhbmdlIG9mIHRlbXBlcmF0dXJlcy4gCgpgYGB7ciBoYWxkYW5lLWNvbXAtcGxvdCwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTJ9CmVhcmx5X3BlYWsgPSBmdWxsX2RhdGEgJT4lIAogIGZpbHRlcihzZWFzb24gJWluJSBjKCJlYXJseSIsICJwZWFrIikpICU+JSAKICBtdXRhdGUoc2Vhc29uID0gaWZfZWxzZShzZWFzb24gPT0gImVhcmx5IiwgIm9uZSIsICJ0d28iKSkgJT4lIAogIGdyb3VwX2J5KHNpdGUpICU+JSAKICBtdXRhdGUoY3RtYXhfc2RfcCA9IHNkKGN0bWF4KSwKICAgICAgICAgc2l6ZV9zZF9wID0gc2Qoc2l6ZSksIAogICAgICAgICB0ZW1wX2NoYW5nZSA9IG1heChjb2xsZWN0aW9uX3RlbXApIC0gbWluKGNvbGxlY3Rpb25fdGVtcCksCiAgICAgICAgIGF2Z190ZW1wID0gKG1heChjb2xsZWN0aW9uX3RlbXApICsgbWluKGNvbGxlY3Rpb25fdGVtcCkpIC8gMiwKICAgICAgICAgZGF5c19wYXNzZWQgPSBtYXgoZG95KSAtIG1pbihkb3kpKSAlPiUgCiAgc2VsZWN0KHNpdGUsIGxhdCwgc2Vhc29uLCAKICAgICAgICAgY3RtYXhfc2RfcCwgc2l6ZV9zZF9wLCAKICAgICAgICAgdGVtcF9jaGFuZ2UsIGF2Z190ZW1wLCBkYXlzX3Bhc3NlZCwgCiAgICAgICAgIGN0bWF4LCBzaXplKSAlPiUKICBncm91cF9ieShzaXRlLCBsYXQsIHNlYXNvbiwgCiAgICAgICAgICAgY3RtYXhfc2RfcCwgc2l6ZV9zZF9wLCAKICAgICAgICAgICB0ZW1wX2NoYW5nZSwgYXZnX3RlbXAsIGRheXNfcGFzc2VkKSAlPiUgCiAgc3VtbWFyaXplKGN0bWF4ID0gbWVhbihjdG1heCksCiAgICAgICAgICAgIHNpemUgPSBtZWFuKHNpemUpKSAlPiUgCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGMoc2l0ZSwgbGF0LCBjdG1heF9zZF9wLCBzaXplX3NkX3AsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHRlbXBfY2hhbmdlLCBhdmdfdGVtcCwgZGF5c19wYXNzZWQpLCAKICAgICAgICAgICAgICBuYW1lc19mcm9tID0gc2Vhc29uLCAKICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IGMoY3RtYXgsIHNpemUpKSAlPiUgCiAgbXV0YXRlKHNlYXNvbiA9ICJlYXJseV90b19wZWFrIikgJT4lICAKICBkcm9wX25hKCkKCnBlYWtfbGF0ZSA9IGZ1bGxfZGF0YSAlPiUgCiAgZmlsdGVyKHNlYXNvbiAlaW4lIGMoInBlYWsiLCAibGF0ZSIpKSAlPiUgCiAgbXV0YXRlKHNlYXNvbiA9IGlmX2Vsc2Uoc2Vhc29uID09ICJwZWFrIiwgIm9uZSIsICJ0d28iKSkgJT4lIAogIGdyb3VwX2J5KHNpdGUpICU+JSAKICBtdXRhdGUoY3RtYXhfc2RfcCA9IHNkKGN0bWF4KSwKICAgICAgICAgc2l6ZV9zZF9wID0gc2Qoc2l6ZSksIAogICAgICAgICB0ZW1wX2NoYW5nZSA9IGxhc3QoY29sbGVjdGlvbl90ZW1wKSAtIGZpcnN0KGNvbGxlY3Rpb25fdGVtcCksCiAgICAgICAgIGF2Z190ZW1wID0gKG1heChjb2xsZWN0aW9uX3RlbXApICsgbWluKGNvbGxlY3Rpb25fdGVtcCkpIC8gMiwKICAgICAgICAgZGF5c19wYXNzZWQgPSBtYXgoZG95KSAtIG1pbihkb3kpKSAlPiUgCiAgc2VsZWN0KHNpdGUsIGxhdCwgc2Vhc29uLCBjdG1heF9zZF9wLCBzaXplX3NkX3AsIAogICAgICAgICB0ZW1wX2NoYW5nZSwgYXZnX3RlbXAsIGRheXNfcGFzc2VkLCAKICAgICAgICAgY3RtYXgsIHNpemUpICU+JQogIGdyb3VwX2J5KHNpdGUsIGxhdCwgc2Vhc29uLCBjdG1heF9zZF9wLCBzaXplX3NkX3AsIAogICAgICAgICAgIHRlbXBfY2hhbmdlLCBhdmdfdGVtcCwgZGF5c19wYXNzZWQpICU+JSAKICBzdW1tYXJpemUoY3RtYXggPSBtZWFuKGN0bWF4KSwKICAgICAgICAgICAgc2l6ZSA9IG1lYW4oc2l6ZSkpICU+JSAKICBwaXZvdF93aWRlcihpZF9jb2xzID0gYyhzaXRlLCBsYXQsIGN0bWF4X3NkX3AsIHNpemVfc2RfcCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGVtcF9jaGFuZ2UsIGF2Z190ZW1wLCBkYXlzX3Bhc3NlZCksIAogICAgICAgICAgICAgIG5hbWVzX2Zyb20gPSBzZWFzb24sIAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gYyhjdG1heCwgc2l6ZSkpICU+JSAKICBtdXRhdGUoc2Vhc29uID0gInBlYWtfdG9fbGF0ZSIpICU+JSAgCiAgZHJvcF9uYSgpCgpjYWxjX2hhbGRzID0gZnVuY3Rpb24oeDEsIHgyLCBzZF9wLCBnKXsKICAoKHgyIC8gc2RfcCkgLSAoeDEgLyBzZF9wKSkgLyBnCn0KCmhhbGRhbmVzID0gYmluZF9yb3dzKGVhcmx5X3BlYWssIHBlYWtfbGF0ZSkgJT4lIAogIG11dGF0ZSgiZ2VuX3RpbWUiID0gNTQ5MCooYXZnX3RlbXAgKyAxKV4tMi4wNSwgCiAgICAgICAgICJnZW5zIiA9IGZsb29yKGRheXNfcGFzc2VkIC8gZ2VuX3RpbWUpLAogICAgICAgICAiY3RtYXhfaGFsZGFuZXMiID0gY2FsY19oYWxkcyh4MiA9IGN0bWF4X3R3bywgeDEgPSBjdG1heF9vbmUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZF9wID0gY3RtYXhfc2RfcCwgZyA9IGdlbnMpLAogICAgICAgICAic2l6ZV9oYWxkYW5lcyIgPSBjYWxjX2hhbGRzKHgyID0gc2l6ZV90d28sIHgxID0gc2l6ZV9vbmUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkX3AgPSBzaXplX3NkX3AsIGcgPSBnZW5zKSkKCiMgaGFsZGFuZXMgJT4lIAojICAgdW5ncm91cCgpICU+JSAKIyAgIHNlbGVjdChzaXRlLCB0ZW1wX2NoYW5nZSwgc2Vhc29uLCBjdG1heF9oYWxkYW5lcywgc2l6ZV9oYWxkYW5lcykgJT4lIAojICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKGN0bWF4X2hhbGRhbmVzLCBzaXplX2hhbGRhbmVzKSwKIyAgICAgICAgICAgICAgICBuYW1lc190byA9IGMoInR5cGUiLCBOQSksIAojICAgICAgICAgICAgICAgIG5hbWVzX3NlcCA9ICJfIiwKIyAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiaGFsZGFuZXMiKSAlPiUgCiMgICBnZ3Bsb3QoYWVzKHggPSB0eXBlLCB5ID0gaGFsZGFuZXMsIGdyb3VwID0gc2l0ZSwgY29sb3VyID0gc2l0ZSkpICsgCiMgICBmYWNldF93cmFwKHNlYXNvbn4uKSArIAojICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKyAKIyAgIGdlb21fbGluZShhZXMobGluZXdpZHRoID0gZGVzYyh0ZW1wX2NoYW5nZSkpKSArIAojICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiMgICBsYWJzKHggPSAiVHJhaXQiLCAKIyAgICAgICAgeSA9ICJIYWxkYW5lcyIsIAojICAgICAgICBsaW5ld2lkdGggPSAiVGVtcC4gQ2hhbmdlIikgKyAKIyAgIHRoZW1lX21hdHRfZmFjZXRzKCkKCmN0bWF4X2hhbGRzX3Bsb3QgPSBoYWxkYW5lcyAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBzZWxlY3Qoc2l0ZSwgdGVtcF9jaGFuZ2UsIHNlYXNvbiwgY3RtYXhfaGFsZGFuZXMsIHNpemVfaGFsZGFuZXMpICU+JSAgIAogIGdncGxvdChhZXMoeCA9IHNlYXNvbiwgeSA9IGN0bWF4X2hhbGRhbmVzLCBjb2xvdXIgPSBzaXRlLCBncm91cCA9IHNpdGUpKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG91ciA9ICJncmV5NzAiKSArIAogIGdlb21fbGluZShsaW5ld2lkdGggPSAyKSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2l0ZV9jb2xzKSArIAogIGxhYnMoeCA9ICJTZWFzb24iLAogICAgICAgeSA9ICJIYWxkYW5lcyIpICsgCiAgZ2d0aXRsZSgiQ1RtYXgiKSArIAogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCgpzaXplX2hhbGRzX3Bsb3QgPSBoYWxkYW5lcyAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBzZWxlY3Qoc2l0ZSwgdGVtcF9jaGFuZ2UsIHNlYXNvbiwgY3RtYXhfaGFsZGFuZXMsIHNpemVfaGFsZGFuZXMpICU+JSAgIAogIGdncGxvdChhZXMoeCA9IHNlYXNvbiwgeSA9IHNpemVfaGFsZGFuZXMsIGNvbG91ciA9IHNpdGUsIGdyb3VwID0gc2l0ZSkpICsgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3VyID0gImdyZXk3MCIpICsgCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDIpICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiAgbGFicyh4ID0gIlNlYXNvbiIsCiAgICAgICB5ID0gIkhhbGRhbmVzIikgKyAKICBnZ3RpdGxlKCJTaXplIikgKyAKICB0aGVtZV9tYXR0KCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQoKZ2dhcnJhbmdlKGN0bWF4X2hhbGRzX3Bsb3QsIHNpemVfaGFsZHNfcGxvdCwgY29tbW9uLmxlZ2VuZCA9IFQsIGxlZ2VuZCA9ICJib3R0b20iKQpgYGAKCmBgYHtyIGhhbGRhbmUtcmVzaWRzLWNvbXAtcGxvdCwgZmlnLmhlaWdodD0zLjUsIGZpZy53aWR0aD05LCBpbmNsdWRlID0gRn0KZWFybHlfcGVha19yZXNpZHMgPSB1bml2ZXJzYWxfcmVzaWRzICU+JSAKICBmaWx0ZXIoc2Vhc29uICVpbiUgYygiZWFybHkiLCAicGVhayIpKSAlPiUgCiAgbXV0YXRlKHNlYXNvbiA9IGlmX2Vsc2Uoc2Vhc29uID09ICJlYXJseSIsICJvbmUiLCAidHdvIikpICU+JSAKICBncm91cF9ieShzaXRlKSAlPiUgCiAgbXV0YXRlKGN0bWF4X3NkX3AgPSBzZChjdG1heF9yZXNpZHMpLAogICAgICAgICBzaXplX3NkX3AgPSBzZChzaXplX3Jlc2lkcyksIAogICAgICAgICB0ZW1wX2NoYW5nZSA9IG1heChjb2xsZWN0aW9uX3RlbXApIC0gbWluKGNvbGxlY3Rpb25fdGVtcCksCiAgICAgICAgIGF2Z190ZW1wID0gKG1heChjb2xsZWN0aW9uX3RlbXApICsgbWluKGNvbGxlY3Rpb25fdGVtcCkpIC8gMiwKICAgICAgICAgZGF5c19wYXNzZWQgPSBtYXgoZG95KSAtIG1pbihkb3kpKSAlPiUgCiAgc2VsZWN0KHNpdGUsIGxhdCwgc2Vhc29uLCAKICAgICAgICAgY3RtYXhfc2RfcCwgc2l6ZV9zZF9wLCAKICAgICAgICAgdGVtcF9jaGFuZ2UsIGF2Z190ZW1wLCBkYXlzX3Bhc3NlZCwgCiAgICAgICAgIGN0bWF4X3Jlc2lkcywgc2l6ZV9yZXNpZHMpICU+JQogIGdyb3VwX2J5KHNpdGUsIGxhdCwgc2Vhc29uLCAKICAgICAgICAgICBjdG1heF9zZF9wLCBzaXplX3NkX3AsIAogICAgICAgICAgIHRlbXBfY2hhbmdlLCBhdmdfdGVtcCwgZGF5c19wYXNzZWQpICU+JSAKICBzdW1tYXJpemUoY3RtYXggPSBtZWFuKGN0bWF4X3Jlc2lkcyksCiAgICAgICAgICAgIHNpemUgPSBtZWFuKHNpemVfcmVzaWRzKSkgJT4lIAogIHBpdm90X3dpZGVyKGlkX2NvbHMgPSBjKHNpdGUsIGxhdCwgY3RtYXhfc2RfcCwgc2l6ZV9zZF9wLCAKICAgICAgICAgICAgICAgICAgICAgICAgICB0ZW1wX2NoYW5nZSwgYXZnX3RlbXAsIGRheXNfcGFzc2VkKSwgCiAgICAgICAgICAgICAgbmFtZXNfZnJvbSA9IHNlYXNvbiwgCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBjKGN0bWF4LCBzaXplKSkgJT4lIAogIG11dGF0ZShzZWFzb24gPSAiZWFybHlfdG9fcGVhayIpICU+JSAgCiAgZHJvcF9uYSgpCgpwZWFrX2xhdGVfcmVzaWRzID0gdW5pdmVyc2FsX3Jlc2lkcyAlPiUgCiAgZmlsdGVyKHNlYXNvbiAlaW4lIGMoInBlYWsiLCAibGF0ZSIpKSAlPiUgCiAgbXV0YXRlKHNlYXNvbiA9IGlmX2Vsc2Uoc2Vhc29uID09ICJwZWFrIiwgIm9uZSIsICJ0d28iKSkgJT4lIAogIGdyb3VwX2J5KHNpdGUpICU+JSAKICBtdXRhdGUoY3RtYXhfc2RfcCA9IHNkKGN0bWF4X3Jlc2lkcyksCiAgICAgICAgIHNpemVfc2RfcCA9IHNkKHNpemVfcmVzaWRzKSwgCiAgICAgICAgIHRlbXBfY2hhbmdlID0gbGFzdChjb2xsZWN0aW9uX3RlbXApIC0gZmlyc3QoY29sbGVjdGlvbl90ZW1wKSwKICAgICAgICAgYXZnX3RlbXAgPSAobWF4KGNvbGxlY3Rpb25fdGVtcCkgKyBtaW4oY29sbGVjdGlvbl90ZW1wKSkgLyAyLAogICAgICAgICBkYXlzX3Bhc3NlZCA9IG1heChkb3kpIC0gbWluKGRveSkpICU+JSAKICBzZWxlY3Qoc2l0ZSwgbGF0LCBzZWFzb24sIGN0bWF4X3NkX3AsIHNpemVfc2RfcCwgCiAgICAgICAgIHRlbXBfY2hhbmdlLCBhdmdfdGVtcCwgZGF5c19wYXNzZWQsIAogICAgICAgICBjdG1heF9yZXNpZHMsIHNpemVfcmVzaWRzKSAlPiUKICBncm91cF9ieShzaXRlLCBsYXQsIHNlYXNvbiwgY3RtYXhfc2RfcCwgc2l6ZV9zZF9wLCAKICAgICAgICAgICB0ZW1wX2NoYW5nZSwgYXZnX3RlbXAsIGRheXNfcGFzc2VkKSAlPiUgCiAgc3VtbWFyaXplKGN0bWF4ID0gbWVhbihjdG1heF9yZXNpZHMpLAogICAgICAgICAgICBzaXplID0gbWVhbihzaXplX3Jlc2lkcykpICU+JSAKICBwaXZvdF93aWRlcihpZF9jb2xzID0gYyhzaXRlLCBsYXQsIGN0bWF4X3NkX3AsIHNpemVfc2RfcCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGVtcF9jaGFuZ2UsIGF2Z190ZW1wLCBkYXlzX3Bhc3NlZCksIAogICAgICAgICAgICAgIG5hbWVzX2Zyb20gPSBzZWFzb24sIAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gYyhjdG1heCwgc2l6ZSkpICU+JSAKICBtdXRhdGUoc2Vhc29uID0gInBlYWtfdG9fbGF0ZSIpICU+JSAgCiAgZHJvcF9uYSgpCgpjYWxjX2hhbGRzID0gZnVuY3Rpb24oeDEsIHgyLCBzZF9wLCBnKXsKICAoKHgyIC8gc2RfcCkgLSAoeDEgLyBzZF9wKSkgLyBnCn0KCmhhbGRhbmVzX3Jlc2lkcyA9IGJpbmRfcm93cyhlYXJseV9wZWFrX3Jlc2lkcywgcGVha19sYXRlX3Jlc2lkcykgJT4lIAogIG11dGF0ZSgiZ2VuX3RpbWUiID0gNTQ5MCooYXZnX3RlbXAgKyAxKV4tMi4wNSwgCiAgICAgICAgICJnZW5zIiA9IGZsb29yKGRheXNfcGFzc2VkIC8gZ2VuX3RpbWUpLAogICAgICAgICAiY3RtYXhfaGFsZGFuZXMiID0gY2FsY19oYWxkcyh4MiA9IGN0bWF4X3R3bywgeDEgPSBjdG1heF9vbmUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZF9wID0gY3RtYXhfc2RfcCwgZyA9IGdlbnMpLAogICAgICAgICAic2l6ZV9oYWxkYW5lcyIgPSBjYWxjX2hhbGRzKHgyID0gc2l6ZV90d28sIHgxID0gc2l6ZV9vbmUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkX3AgPSBzaXplX3NkX3AsIGcgPSBnZW5zKSkKCiMgaGFsZGFuZXNfcmVzaWRzICU+JSAKIyAgIHVuZ3JvdXAoKSAlPiUgCiMgICBzZWxlY3Qoc2l0ZSwgdGVtcF9jaGFuZ2UsIHNlYXNvbiwgY3RtYXhfaGFsZGFuZXMsIHNpemVfaGFsZGFuZXMpICU+JSAKIyAgIHBpdm90X2xvbmdlcihjb2xzID0gYyhjdG1heF9oYWxkYW5lcywgc2l6ZV9oYWxkYW5lcyksCiMgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSBjKCJ0eXBlIiwgTkEpLCAKIyAgICAgICAgICAgICAgICBuYW1lc19zZXAgPSAiXyIsCiMgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gImhhbGRhbmVzIikgJT4lIAojICAgZ2dwbG90KGFlcyh4ID0gdHlwZSwgeSA9IGhhbGRhbmVzLCBncm91cCA9IHNpdGUsIGNvbG91ciA9IHNpdGUpKSArIAojICAgZmFjZXRfd3JhcChzZWFzb25+LikgKyAKIyAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsgCiMgICBnZW9tX2xpbmUoYWVzKGxpbmV3aWR0aCA9IGRlc2ModGVtcF9jaGFuZ2UpKSkgKyAKIyAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2l0ZV9jb2xzKSArIAojICAgbGFicyh4ID0gIlRyYWl0IiwgCiMgICAgICAgIHkgPSAiSGFsZGFuZXMiLCAKIyAgICAgICAgbGluZXdpZHRoID0gIlRlbXAuIENoYW5nZSIpICsgCiMgICB0aGVtZV9tYXR0X2ZhY2V0cygpCgoKcmVzaWRzX2N0bWF4X2hhbGRzX3Bsb3QgPSBoYWxkYW5lc19yZXNpZHMgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgc2VsZWN0KHNpdGUsIHRlbXBfY2hhbmdlLCBzZWFzb24sIGN0bWF4X2hhbGRhbmVzLCBzaXplX2hhbGRhbmVzKSAlPiUgICAKICBnZ3Bsb3QoYWVzKHggPSBzZWFzb24sIHkgPSBjdG1heF9oYWxkYW5lcywgY29sb3VyID0gc2l0ZSwgZ3JvdXAgPSBzaXRlKSkgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvdXIgPSAiZ3JleTcwIikgKyAKICBnZW9tX2xpbmUobGluZXdpZHRoID0gMikgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNpdGVfY29scykgKyAKICBsYWJzKHggPSAiU2Vhc29uIiwKICAgICAgIHkgPSAiSGFsZGFuZXMiKSArIAogIGdndGl0bGUoIkNUbWF4IikgKyAKICB0aGVtZV9tYXR0KCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQoKcmVzaWRzX3NpemVfaGFsZHNfcGxvdCA9IGhhbGRhbmVzX3Jlc2lkcyAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBzZWxlY3Qoc2l0ZSwgdGVtcF9jaGFuZ2UsIHNlYXNvbiwgY3RtYXhfaGFsZGFuZXMsIHNpemVfaGFsZGFuZXMpICU+JSAgIAogIGdncGxvdChhZXMoeCA9IHNlYXNvbiwgeSA9IHNpemVfaGFsZGFuZXMsIGNvbG91ciA9IHNpdGUsIGdyb3VwID0gc2l0ZSkpICsgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3VyID0gImdyZXk3MCIpICsgCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDIpICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiAgbGFicyh4ID0gIlNlYXNvbiIsCiAgICAgICB5ID0gIkhhbGRhbmVzIikgKyAKICBnZ3RpdGxlKCJTaXplIikgKyAKICB0aGVtZV9tYXR0KCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQoKZ2dhcnJhbmdlKHJlc2lkc19jdG1heF9oYWxkc19wbG90LCByZXNpZHNfc2l6ZV9oYWxkc19wbG90LCBjb21tb24ubGVnZW5kID0gVCwgbGVnZW5kID0gImJvdHRvbSIpCmBgYAoKYGBge3IgaGFsZGFuZXMtbGF0LXBsb3QsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD04LCBpbmNsdWRlID0gRn0KIyBTaG93biBiZWxvdyBhcmUgdGhlIGhhbGRhbmUgdmFsdWVzIHBsb3R0ZWQgYWdhaW5zdCBsYXRpdHVkZS4gTm90ZSB0aGF0IGV2ZW4gdGhvdWdoIGxhcmdlIGNoYW5nZXMgaW4gdGVtcGVyYXR1cmUgb2NjdXJyZWQgYmV0d2VlbiBwZWFrIGFuZCBsYXRlIHNhbXBsZXMgaW4gdGhlIENoZXNhcGVha2UsIHRoZSBjaGFuZ2UgaW4gaGFsZGFuZXMgaXMgcmVsYXRpdmVseSBzbWFsbCwgd2hpbGUgaW4gdGhlIE5vcnRoZXJuIHBvcHVsYXRpb25zLCBjaGFuZ2VzIGFyZSBsYXJnZXIsIHRob3VnaCBtb3JlIHZhcmlhYmxlLiAKCmN0bWF4X2hhbGRhbmVzID0gZ2dwbG90KGhhbGRhbmVzLCBhZXMoeCA9IGxhdCwgeSA9IGN0bWF4X2hhbGRhbmVzLCBjb2xvdXIgPSBzaXRlLCBzaGFwZSA9IHNlYXNvbikpICsgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAzKSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2l0ZV9jb2xzKSArIAogIGxhYnMoeCA9ICJMYXRpdHVkZSIsCiAgICAgICB5ID0gIkNoYW5nZSBpbiBDVG1heCAoaGFsZGFuZXMpIikgKyAKICB0aGVtZV9tYXR0X2ZhY2V0cygpCgpzaXplX2hhbGRhbmVzID0gZ2dwbG90KGhhbGRhbmVzLCBhZXMoeCA9IGxhdCwgeSA9IHNpemVfaGFsZGFuZXMsIGNvbG91ciA9IHNpdGUsIHNoYXBlID0gc2Vhc29uKSkgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiAgbGFicyh4ID0gIkxhdGl0dWRlIiwKICAgICAgIHkgPSAiQ2hhbmdlIGluIFNpemUgKGhhbGRhbmVzKSIpICsgCiAgdGhlbWVfbWF0dF9mYWNldHMoKQoKZ2dhcnJhbmdlKGN0bWF4X2hhbGRhbmVzLCBzaXplX2hhbGRhbmVzLCBjb21tb24ubGVnZW5kID0gVCwgbGVnZW5kID0gInJpZ2h0IiwgbnJvdyA9IDIpCmBgYAoKIyMgV2h5IGRvZXMgaW50cmFzcGVjaWZpYyBkYXRhIG1hdHRlcj8gCgpUaGVybWFsIGxpbWl0cyB2YXJ5IHN1YnN0YW50aWFsbHkgYWNyb3NzIGJvdGggc3BhdGlhbCBhbmQgdGVtcG9yYWwgc2NhbGVzIGluIHRoaXMgc3BlY2llcywgaGlnaGxpZ2h0aW5nIHRoZSBpbXBvcnRhbmNlIG9mIGNvbnNpZGVyaW5nIGJvdGggaW50cmFzcGVjaWZpYyBhbmQgdGVtcG9yYWwgdmFyaWF0aW9uIGluIHRoZXJtYWwgbGltaXRzIGZvciBwcmVkaWN0aW9ucyBvZiB2dWxuZXJhYmlsaXR5IHRvIGNsaW1hdGUgY2hhbmdlLiBTaW5nbGUgcG9pbnQgZXN0aW1hdGVzIG9mIHRoZXJtYWwgbGltaXRzIChhcyBjb21tb25seSB1c2VkIGluIGxhcmdlciwgZ2VuZXJhbCBhbmFseXNlcyBhY3Jvc3MgdGF4YSkgb2JzY3VyZSB0aGlzIGNydWNpYWwgdmFyaWF0aW9uLCBhbmQgbWF5IGJpYXMgb3VyIGVzdGltYXRlcyBvZiBzcGF0aWFsIHBhdHRlcm5zIGluIHZ1bG5lcmFiaWxpdHkuIEhlcmUgd2UgZXhwbG9yZSB0aHJlZSBzZXBhcmF0ZSBzY2VuYXJpb3MgdG8gaWxsdXN0cmF0ZSBhbmQgcXVhbnRpZnkgdGhlIGltcG9ydGFuY2Ugb2YgdGhpcyBpbnRyYXNwZWNpZmljIHZ1bG5lcmFiaWxpdHkuIAoKIyMjIFNjZW5hcmlvIDEgLSBJbnZhcmlhbnQgdGhlcm1hbCBsaW1pdHMKClRoZSBmaXJzdCBzY2VuYXJpbyBhc3N1bWVzIHRoYXQgdGhlcm1hbCBsaW1pdHMgYXJlIGNvbnN0YW50IGFjcm9zcyBib3RoIHNwYXRpYWwgYW5kIHRlbXBvcmFsIGF4ZXMgKGkuZS4gYSBzaW5nbGUgcG9pbnQgZXN0aW1hdGUgb2YgdGhlIHRoZXJtYWwgbGltaXQgZm9yIHRoaXMgc3BlY2llcykuIEhlcmUgd2Ugc2VsZWN0ZWQgYSBjZW50cmFsIHBvcHVsYXRpb24gKHRoZSBoaWdoIHNhbGluaXR5IENoZXNhcGVha2UgQmF5IHNpdGUpLCBhbmQgdXNlZCB0aGUgYXZlcmFnZSB0aGVybWFsIGxpbWl0IGZyb20gdGhlIHBlYWsgc2Vhc29uIHNhbXBsZSBhcyBvdXIgJ3JlcHJlc2VudGF0aXZlJyB0aGVybWFsIGxpbWl0LiBUaGlzIGFwcHJvYWNoIGlzIHNpbWlsYXIgdG8gdGhhdCB1c2VkIGluIEJlbm5ldCBldCBhbC4gdG8gY29tcGlsZSB0aGUgR2xvYlRoZXJtIGRhdGFzZXQuIFRoZXNlIHRoZXJtYWwgbGltaXRzIGFyZSB1c2VkIHRvIHJlLWVzdGltYXRlIHdhcm1pbmcgdG9sZXJhbmNlIGZvciBlYWNoIGNvbGxlY3Rpb24gKG1lYW4gdGhlcm1hbCBsaW1pdCAtIGNvbGxlY3Rpb24gdGVtcGVyYXR1cmUpLiBXZSB0aGVuIGNvbXBhcmVkIHRoaXMgcHJlZGljdGVkIHdhcm1pbmcgdG9sZXJhbmNlIHdpdGggdGhlIGFjdHVhbCBvYnNlcnZlZCB3YXJtaW5nIHRvbGVyYW5jZXMgZnJvbSBlYWNoIGNvbGxlY3Rpb24uIEEgcG9zaXRpdmUgZGlmZmVyZW5jZSBpbmRpY2F0ZXMgYW4gb3ZlcmVzdGltYXRlZCB3YXJtaW5nIHRvbGVyYW5jZSAodGhlIHBvcHVsYXRpb24gaXMgYWN0dWFsbHkgY2xvc2VyIHRvIHRoZWlyIHRoZXJtYWwgbGltaXRzIHRoYW4gd291bGQgYmUgcHJlZGljdGVkIGZyb20gdGhlIGVzdGltYXRlZCB2YWx1ZSwgYW5kIHRoZXJlZm9yZSBtb3JlIHZ1bG5lcmFibGUpLiBBIG5lZ2F0aXZlIGRpZmZlcmVuY2UgaW5kaWNhdGVzIGFuIHVuZGVyZXN0aW1hdGVkIHdhcm1pbmcgdG9sZXJhbmNlICh0aGUgcG9wdWxhdGlvbiBpcyBmdXJ0aGVyIGZyb20gdGhlaXIgdGhlcm1hbCBsaW1pdCB0aGFuIHdvdWxkIGJlIHByZWRpY3RlZCwgYW5kIHRoZXJlZm9yZSBsZXNzIHZ1bG5lcmFibGUpLiAKCkJvdGggb3ZlcmVzdGltYXRlcyBhbmQgdW5kZXJlc3RpbWF0ZXMgY2FuIGJlIHByb2JsZW1hdGljIGZvciBhY2N1cmF0ZSBtYW5hZ2VtZW50IGFuZCBjb25zZXJ2YXRpb24gc3RyYXRlZ2llcy4gV2Ugc3VtbWFyaXplIGVhY2ggb2YgdGhlIHNjZW5hcmlvcyB1c2luZyAxKSB0aGUgbnVtYmVyIG9mIHBvcHVsYXRpb25zIHdpdGggYSBkaWZmZXJlbmNlIGJldHdlZW4gZXN0aW1hdGVzID4ywrBDIGluIGVpdGhlciBkaXJlY3Rpb24sIDIpIHRoZSBhdmVyYWdlIG1hZ25pdHVkZSBvZiBkaWZmZXJlbmNlIGZvciB0aGF0IHN1YnNldCBvZiBwb3B1bGF0aW9ucywgYW5kIDMpIHRoZSBzbG9wZSBvZiB0aGUgZGlmZmVyZW5jZSBhZ2FpbnN0IGxhdGl0dWRlLiBFZmZlY3RpdmUgZXN0aW1hdGlvbiBzdHJhdGVnaWVzIHdpbGwgaGF2ZSBhIHNtYWxsIG51bWJlciBvZiBwb3B1bGF0aW9ucyB3aXRoIHVuZGVyLSBvciBvdmVyLWVzdGltYXRlZCB3YXJtaW5nIHRvbGVyYW5jZSwgYSBzbWFsbCBtYWduaXR1ZGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHByZWRpY3RlZCBhbmQgb2JzZXJ2ZWQgd2FybWluZyB0b2xlcmFuY2UsIGFuZCBhIHNoYWxsb3cgbGF0aXR1ZGluYWwgc2xvcGUuIAoKSW4gdGhpcyBmaXJzdCBzY2VuYXJpbyAoc2luZ2xlIHBvaW50IGVzdGltYXRlIG9mIHRoZXJtYWwgbGltaXRzKSwgdGhlIGVmZmVjdGl2ZW5lc3Mgb2YgdGhlIGVzdGltYXRlIHZhcmllZCBhY3Jvc3MgbGF0aXR1ZGUgYW5kIGFjcm9zcyBzZWFzb25zLiBEdXJpbmcgdGhlIGVhcmx5IHNlYXNvbiwgdGhlcm1hbCBsaW1pdHMgZnJvbSB0aGUgY2VudHJhbCBzaXRlIHdlcmUgYSBkZWNlbnQgcHJlZGljdG9yIG9mIHdhcm1pbmcgdG9sZXJhbmNlIGF0IHRoZSBvdGhlciBzaXRlcywgYW5kIHRoZXJlIHdhcyBvbmx5IGEgc2xpZ2h0IGxhdGl0dWRpbmFsIHRyZW5kLiBUaGlzIGxhdGl0dWRpbmFsIHRyZW5kIGluY3JlYXNlZCwgaG93ZXZlciwgZHVyaW5nIHRoZSBwZWFrIGFuZCBsYXRlIHNlYXNvbiBjb2xsZWN0aW9ucywgZHJpdmVuIGJ5IGluY3JlYXNpbmdseSBsYXJnZSBkaWZmZXJlbmNlcyBpbiB0aGUgbm9ydGhlcm4gc2l0ZXMgKGluZGljYXRpbmcgaW5jcmVhc2VkIHZ1bG5lcmFiaWxpdHkgcmVsYXRpdmUgdG8gcHJlZGljdGlvbnMgaW4gdGhlc2Ugc2l0ZXMpLiBEdXJpbmcgdGhlIHBlYWsgc2Vhc29uIGNvbGxlY3Rpb24sIHdhcm1pbmcgdG9sZXJhbmNlIGluIHRoZSBzb3V0aGVybiBzaXRlcyB3YXMgdW5kZXJlc3RpbWF0ZWQgYnkgc2V2ZXJhbCBkZWdyZWVzICh0aGVzZSBwb3B1bGF0aW9ucyB3ZXJlIGxlc3MgdnVsbmVyYWJsZSB0aGFuIHByZWRpY3RlZCBieSB0aGUgY2VudHJhbCBzaXRlIHRoZXJtYWwgbGltaXRzKS4gCgpgYGB7cn0KIyBDb21wYXJlIGVzdGltYXRlZCB3YXJtaW5nIHRvbGVyYW5jZSAicmFuZ2VzIiB3aGVuOiAxKSBDVG1heCBmb3IgImF2ZXJhZ2UiIGNvbGxlY3Rpb24gaXMgdXNlZDsgMikgV2hlbiBDVG1heCBmb3Igb25lIGNvbGxlY3Rpb24gcGVyIHBvcHVsYXRpb24gaXMgdXNlZDsgYW5kIDMpIFdoZW4gYWxsIGNvbGxlY3Rpb25zIGFyZSB1c2VkLiBUaGUgaWRlYSBpcyB0byBzaG93IHRoYXQgbm90IGFjY291bnRpbmcgZm9yIGludHJhLXNwZWNpZmljIGFuZCBpbnRyYS1wb3B1bGF0aW9uIHZhcmlhdGlvbiBsZWFkcyB0byBpbmNvcnJlY3QgcHJlZGljdGlvbnMgb2YgdnVsbmVyYWJpbGl0eSB0byB3YXJtaW5nIGJlY2F1c2UgdGhpcyB2YXJpYXRpb24gY2FuIGJlIHN1YnN0YW50aWFsIC0gYWNyb3NzIHBvcHVsYXRpb25zIHdpdGhpbiBlYWNoIHNlYXNvbmFsIGNvbGxlY3Rpb24sIHRoZXJlIGlzIGF0IGxlYXN0IDXCsEMgdmFyaWF0aW9uIGluIHRoZXJtYWwgbGltaXRzLCB3aGlsZSBhY3Jvc3MgY29sbGVjdGlvbnMgd2l0aGluIHBvcHVsYXRpb25zLCBhY2NsaW1hdGlvbiB0byBjaGFuZ2VzIGluIHRlbXBlcmF0dXJlIGNhbiBkcml2ZSBzdWJzdGFudGlhbCB2YXJpYXRpb24uIAoKIyMgU2NlbmFyaW8gMSAtIHNpbmdsZSBwb2ludCBlc3RpbWF0ZXMgCgplc3RfMSA9IGZ1bGxfZGF0YSAlPiUgCiAgZ3JvdXBfYnkoc2l0ZSwgc2Vhc29uKSAlPiUgCiAgc3VtbWFyaXNlKCJtZWFuX2N0bWF4IiA9IG1lYW4oY3RtYXgpKSAlPiUgCiAgZmlsdGVyKHNpdGUgPT0gIlR5bGVyIENvdmUiLCBzZWFzb24gPT0gInBlYWsiKQoKc2NlbmFyaW9fMSA9IGZ1bGxfZGF0YSAlPiUgCiAgbXV0YXRlKHJlcF9jdG1heCA9IGVzdF8xJG1lYW5fY3RtYXgsCiAgICAgICAgIHByZWRfd3QgPSByZXBfY3RtYXggLSBjb2xsZWN0aW9uX3RlbXAsIAogICAgICAgICB3dF9kaWZmID0gcHJlZF93dCAtIHdhcm1pbmdfdG9sKQoKZ2dwbG90KHNjZW5hcmlvXzEsIGFlcyh4ID0gbGF0LCB5ID0gd3RfZGlmZikpICsgCiAgZmFjZXRfd3JhcChzZWFzb25+LiwgbnJvdyA9IDMpICsgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArIAogIGdlb21fcG9pbnQoKSArIAogIGxhYnMoeCA9ICJMYXRpdHVkZSIsIAogICAgICAgeSA9ICJQcmVkaWN0ZWQgLSBPYnNlcnZlZCBXVCIpICsgCiAgdGhlbWVfbWF0dF9mYWNldHMoKQoKbGF0Lm1vZGVsMSA9IGxtKGRhdGEgPSBzY2VuYXJpb18xLAogICAgICAgICAgICAgICAgd3RfZGlmZiB+IGxhdCpzZWFzb24pCgpsYXRfc2xvcGVfMSA9IGVtbWVhbnM6OmVtdHJlbmRzKGxhdC5tb2RlbDEsIHZhciA9ICJsYXQiLCBzcGVjcyA9ICJzZWFzb24iKSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICBzZWxlY3Qoc2Vhc29uLCBsYXQudHJlbmQpCgpwZXJmb3JtYW5jZV8xID0gc2NlbmFyaW9fMSAlPiUgCiAgc2VsZWN0KHNpdGUsIGxhdCwgc2Vhc29uLCB3dF9kaWZmKSAlPiUgIAogIGdyb3VwX2J5KHNpdGUsIHNlYXNvbiwgbGF0KSAlPiUgCiAgc3VtbWFyaXNlKCJtZWFuX2RpZmYiID0gbWVhbih3dF9kaWZmKSwKICAgICAgICAgICAgImFic19kaWZmIiA9IGFicyhtZWFuX2RpZmYpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBtdXRhdGUoImZsYWciID0gaWZfZWxzZShhYnNfZGlmZiA+PSAyLCAieWVzIiwgIm5vIikpICU+JSAKICBmaWx0ZXIoZmxhZyA9PSAieWVzIikgJT4lICAKICBncm91cF9ieShzZWFzb24pICU+JSAKICBzdW1tYXJpc2UoImF2Z19kaWZmIiA9IG1lYW4oYWJzX2RpZmYpLAogICAgICAgICAgICAibiIgPSBuKCkpICU+JSAKICBpbm5lcl9qb2luKGxhdF9zbG9wZV8xLCBieSA9ICJzZWFzb24iKQpgYGAKCiMjIyBTY2VuYXJpbyAyIC0gU2Vhc29uYWxseSBpbnZhcmlhbnQgdGhlcm1hbCBsaW1pdHMKCkxvY2FsIGFkYXB0YXRpb24gb2YgdGhlcm1hbCBsaW1pdHMgaXMgd2lkZWx5IG9ic2VydmVkIGFjcm9zcyBhIHJhbmdlIG9mIHRheGEsIGluY2x1ZGluZyAqQWNhcnRpYSB0b25zYSouIEluIHRoZSBzZWNvbmQgc2NlbmFyaW8sIHdlIGFjY291bnQgZm9yIHRoaXMgYnkgdXNpbmcgYXZlcmFnZSB0aGVybWFsIGxpbWl0cyBmcm9tIHRoZSBwZWFrIHNlYXNvbiBmb3IgZWFjaCBwb3B1bGF0aW9uIGluIHRoZSBlc3RpbWF0ZXMgb2Ygd2FybWluZyB0b2xlcmFuY2UgdGhyb3VnaG91dCB0aGUgeWVhci4gCgpVbnN1cnByaXNpbmdseSwgdGhpcyBhcHByb2FjaCBlbGltaW5hdGVzIHRoZSBsYXRpdHVkaW5hbCB0cmVuZC4gSW5zdGVhZCB3ZSBzZWUgdGhhdCBwZWFrIHNlYXNvbiBlc3RpbWF0ZXMgd2VyZSBnZW5lcmFsbHkgZGVjZW50IHByZWRpY3RvcnMgb2Ygd2FybWluZyB0b2xlcmFuY2UgZHVyaW5nIHRoZSBlYXJseSBzZWFzb24gKGFsdGhvdWdoIHRoZXJlIHdlcmUgc2xpZ2h0IG92ZXJlc3RpbWF0ZXMgaW4gc2V2ZXJhbCBwb3B1bGF0aW9ucyksIGFuZCBzbGlnaHRseSB1bmRlcmVzdGltYXRlZCB3YXJtaW5nIHRvbGVyYW5jZSBkdXJpbmcgdGhlIGxhdGUgc2Vhc29uLgoKYGBge3J9CmVzdF8yID0gZnVsbF9kYXRhICU+JSAKICBncm91cF9ieShzaXRlLCBzZWFzb24pICU+JSAKICBzdW1tYXJpc2UoIm1lYW5fY3RtYXgiID0gbWVhbihjdG1heCkpICU+JSAKICBmaWx0ZXIoc2Vhc29uID09ICJwZWFrIikgJT4lIAogIHNlbGVjdChzaXRlLCBtZWFuX2N0bWF4KQoKc2NlbmFyaW9fMiA9IGZ1bGxfZGF0YSAlPiUgCiAgaW5uZXJfam9pbihlc3RfMiwgYnkgPSBjKCJzaXRlIikpICU+JSAKICBtdXRhdGUocHJlZF93dCA9IG1lYW5fY3RtYXggLSBjb2xsZWN0aW9uX3RlbXAsIAogICAgICAgICB3dF9kaWZmID0gcHJlZF93dCAtIHdhcm1pbmdfdG9sKQoKZ2dwbG90KHNjZW5hcmlvXzIsIGFlcyh4ID0gbGF0LCB5ID0gd3RfZGlmZikpICsgCiAgZmFjZXRfd3JhcChzZWFzb25+LiwgbnJvdyA9IDMpICsgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArIAogIGdlb21fcG9pbnQoKSArIAogIGxhYnMoeCA9ICJMYXRpdHVkZSIsIAogICAgICAgeSA9ICJQcmVkaWN0ZWQgLSBPYnNlcnZlZCBXVCIpICsgCiAgdGhlbWVfbWF0dF9mYWNldHMoKQoKbGF0Lm1vZGVsMiA9IGxtKGRhdGEgPSBzY2VuYXJpb18yLAogICAgICAgICAgICAgICAgd3RfZGlmZiB+IGxhdCpzZWFzb24pCgpsYXRfc2xvcGVfMiA9IGVtbWVhbnM6OmVtdHJlbmRzKGxhdC5tb2RlbDIsIHZhciA9ICJsYXQiLCBzcGVjcyA9ICJzZWFzb24iKSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICBzZWxlY3Qoc2Vhc29uLCBsYXQudHJlbmQpCgpwZXJmb3JtYW5jZV8yID0gc2NlbmFyaW9fMiAlPiUgCiAgc2VsZWN0KHNpdGUsIGxhdCwgc2Vhc29uLCB3dF9kaWZmKSAlPiUgIAogIGdyb3VwX2J5KHNpdGUsIHNlYXNvbiwgbGF0KSAlPiUgCiAgc3VtbWFyaXNlKCJtZWFuX2RpZmYiID0gbWVhbih3dF9kaWZmKSwKICAgICAgICAgICAgImFic19kaWZmIiA9IGFicyhtZWFuX2RpZmYpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBtdXRhdGUoImZsYWciID0gaWZfZWxzZShhYnNfZGlmZiA+PSAyLCAieWVzIiwgIm5vIikpICU+JSAKICBmaWx0ZXIoZmxhZyA9PSAieWVzIikgJT4lICAKICBncm91cF9ieShzZWFzb24pICU+JSAKICBzdW1tYXJpc2UoImF2Z19kaWZmIiA9IG1lYW4oYWJzX2RpZmYpLAogICAgICAgICAgICAibiIgPSBuKCkpICU+JSAgCiAgaW5uZXJfam9pbihsYXRfc2xvcGVfMiwgYnkgPSBjKCJzZWFzb24iKSkKYGBgCgojIyMgU2NlbmFyaW8gMyAtIFBvcHVsYXRpb24gc3ViLXNhbXBsaW5nIAoKQm90aCBvZiB0aGUgcHJldmlvdXMgYXBwcm9hY2hlcyB0byBlc3RpbWF0aW5nIHdhcm1pbmcgdG9sZXJhbmNlIHJlc3VsdCBpbiBvdmVyZXN0aW1hdGVzIG9mIHdhcm1pbmcgdG9sZXJhbmNlLiBUaGVzZSByZWR1Y3RpdmUgbWV0aG9kcyBpbmNyZWFzZSB0aGUgZmVhc2liaWxpdHksIGJ1dCBhcmUgdW5hYmxlIHRvIGFjY291bnQgZm9yIHRoZSBjby1vY2N1cmluZyBzaGlmdHMgaW4gYW1iaWVudCB0ZW1wZXJhdHVyZSBhbmQgdGhlcm1hbCBsaW1pdHMuIENvbnRpbnVvdXMgaW4tc2l0dSBtb25pdG9yaW5nIG9mIHRoZXJtYWwgbGltaXRzIGlzIGltcHJhY3RpY2FsLCBob3dldmVyLCBlc3BlY2lhbGx5IGZvciBzcGVjaWVzIHdpdGggc21hbGwgcG9wdWF0aW9uIHNpemVzIGFuZC9vciB2ZXJ5IGxhcmdlIHJhbmdlIGRpc3RyaWJ1dGlvbnMuIE9uZSBwb3RlbnRpYWwgY29tcHJvbWlzZSBzb2x1dGlvbiBpcyB0byBzdWItc2FtcGxlIHBvcHVsYXRpb25zIGFuZCB1c2Ugb2JzZXJ2ZWQgZGF0YSB0byBwcmVkaWN0IHNwYXRpYWwgYW5kIHNlYXNvbmFsIGNoYW5nZXMgaW4gd2FybWluZyB0b2xlcmFuY2UuIAoKSW4gdGhpcyB0aGlyZCBhcHByb2FjaCwgd2UgcmFuZG9tbHkgc2VsZWN0ZWQgbmluZSBjb2xsZWN0aW9ucywgZml0IGEgbGluZWFyIG1vZGVsIG9mIENUbWF4IH4gY29sbGVjdGlvbiB0ZW1wZXJhdHVyZSwgYW5kIHVzZWQgdGhpcyByZWdyZXNzaW9uIHRvIHByZWRpY3QgdGhlcm1hbCBsaW1pdHMgYW5kIHdhcm1pbmcgdG9sZXJhbmNlIGFjcm9zcyB0aGUgZnVsbCBzZXQgb2YgY29sbGVjdGlvbnMuIFRoZXNlIHByZWRpY3RlZCB3YXJtaW5nIHRvbGVyYW5jZSB2YWx1ZXMgd2VyZSB0aGVuIGNvbXBhcmVkIGFnYWluc3Qgb2JzZXJ2ZWQgd2FybWluZyB0b2xlcmFuY2UgYXMgYmVmb3JlLiBXZSByZXBlYXRlZCB0aGlzIHByb2Nlc3MgMTAwIHRpbWVzICgxMDAgcmFuZG9tIHNldHMgb2YgOSBjb2xsZWN0aW9ucykgdG8gZXhhbWluZSB0aGUgc2Vuc2l0aXZpdHkgb2YgdGhpcyBhcHByb2FjaCB0aGUgcG9wdWxhdGlvbnMgYW5kIHNlYXNvbnMgY29sbGVjdGVkLiBJbiBhZGRpdGlvbiB0byB0aGlzIHJhbmRvbSBkYXRhLCB3ZSBhbHNvIGluY2x1ZGVkIGEgc2NlbmFyaW8gd2hlcmUgYWxsIHNlYXNvbmFsIGNvbGxlY3Rpb25zIGZyb20gRnQuIEhhbWVyLCBUeWxlciBDb3ZlLCBhbmQgTWlyYW1pY2hpICh0aGUgbGF0aXR1ZGluYWwgZXh0cmVtZXMgYW5kIGEgY2VudHJhbCBwb2ludCkgd2VyZSB1c2VkIHRvIHByZWRpY3QgdGhlcm1hbCBsaW1pdHMuIAoKYGBge3J9CgpzY2VuYXJpb18zID0gZGF0YS5mcmFtZSgpCnBlcmZvcm1hbmNlXzMgPSBkYXRhLmZyYW1lKCkKCmZvcihpIGluIDE6MTAwKXsKICAKICBlc3RfMyA9IGZ1bGxfZGF0YSAlPiUgCiAgICBncm91cF9ieShzaXRlLCBzZWFzb24sIGNvbGxlY3Rpb25fdGVtcCkgJT4lIAogICAgc3VtbWFyaXNlKCJtZWFuX2N0bWF4IiA9IG1lYW4oY3RtYXgpLCAuZ3JvdXBzID0gImtlZXAiKSAlPiUgCiAgICB1bmdyb3VwKCkgJT4lIAogICAgZmlsdGVyKHJvd19udW1iZXIoKSAlaW4lIHNhbXBsZShjKDE6bWF4KHJvd19udW1iZXIoKSkpLCBzaXplID0gOSwgcmVwbGFjZSA9IEYpKQogIAogIHJlcC5tb2RlbCA9IGxtKGRhdGEgPSBlc3RfMywgbWVhbl9jdG1heCB+IGNvbGxlY3Rpb25fdGVtcCkKICAKICByZXBfZGF0YSA9IGZ1bGxfZGF0YSAlPiUgCiAgICBncm91cF9ieShzaXRlLCBzZWFzb24pICU+JSAgCiAgICBtdXRhdGUobWVhbl93dCA9IG1lYW4od2FybWluZ190b2wpKSAlPiUgCiAgICBzZWxlY3Qoc2l0ZSwgc2Vhc29uLCBjb2xsZWN0aW9uX3RlbXAsIGxhdCwgbWVhbl93dCkgJT4lIAogICAgdW5ncm91cCgpICU+JSAKICAgIGRpc3RpbmN0KCkgJT4lICAKICAgIG11dGF0ZShwcmVkX2N0bWF4ID0gcHJlZGljdChyZXAubW9kZWwsIG5ld2RhdGEgPSAuKSwKICAgICAgICAgICBwcmVkX3d0ID0gcHJlZF9jdG1heCAtIGNvbGxlY3Rpb25fdGVtcCwKICAgICAgICAgICB3dF9kaWZmID0gcHJlZF93dCAtIG1lYW5fd3QsCiAgICAgICAgICAgcnVuID0gaSwKICAgICAgICAgICBncm91cCA9ICJyYW5kb20iKQogIAogIHNjZW5hcmlvXzMgPSBiaW5kX3Jvd3Moc2NlbmFyaW9fMywgcmVwX2RhdGEpCiAgCiAgbGF0Lm1vZGVsMyA9IGxtKGRhdGEgPSBzY2VuYXJpb18zLAogICAgICAgICAgICAgICAgICB3dF9kaWZmIH4gbGF0KnNlYXNvbikKICAKICBsYXRfc2xvcGVfMyA9IGVtbWVhbnM6OmVtdHJlbmRzKGxhdC5tb2RlbDMsIHZhciA9ICJsYXQiLCBzcGVjcyA9ICJzZWFzb24iKSAlPiUgCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgc2VsZWN0KHNlYXNvbiwgbGF0LnRyZW5kKQogIAogIHJlcF9wZXJmb3JtYW5jZSA9IHNjZW5hcmlvXzMgJT4lIAogICAgc2VsZWN0KHNpdGUsIGxhdCwgc2Vhc29uLCB3dF9kaWZmKSAlPiUgIAogICAgZ3JvdXBfYnkoc2l0ZSwgc2Vhc29uLCBsYXQpICU+JSAKICAgIHN1bW1hcmlzZSgibWVhbl9kaWZmIiA9IG1lYW4od3RfZGlmZiksCiAgICAgICAgICAgICAgImFic19kaWZmIiA9IGFicyhtZWFuX2RpZmYpLCAKICAgICAgICAgICAgICAuZ3JvdXBzID0gImtlZXAiKSAlPiUgCiAgICB1bmdyb3VwKCkgJT4lIAogICAgbXV0YXRlKCJmbGFnIiA9IGlmX2Vsc2UoYWJzX2RpZmYgPj0gMiwgInllcyIsICJubyIpKSAlPiUgCiAgICBmaWx0ZXIoZmxhZyA9PSAieWVzIikgJT4lICAKICAgIGdyb3VwX2J5KHNlYXNvbikgJT4lIAogICAgc3VtbWFyaXNlKCJhdmdfZGlmZiIgPSBtZWFuKGFic19kaWZmKSwKICAgICAgICAgICAgICAibiIgPSBuKCksCiAgICAgICAgICAgICAgLmdyb3VwcyA9ICJrZWVwIikgJT4lICAKICAgIGlubmVyX2pvaW4obGF0X3Nsb3BlXzMsIGJ5ID0gYygic2Vhc29uIikpCiAgCiAgcGVyZm9ybWFuY2VfMyA9IGJpbmRfcm93cyhwZXJmb3JtYW5jZV8zLCByZXBfcGVyZm9ybWFuY2UpCiAgCn0KCmdvbGRfc3RhbmQgPSBmdWxsX2RhdGEgJT4lIAogIGdyb3VwX2J5KHNpdGUsIHNlYXNvbiwgY29sbGVjdGlvbl90ZW1wKSAlPiUgCiAgc3VtbWFyaXNlKCJtZWFuX2N0bWF4IiA9IG1lYW4oY3RtYXgpLCAuZ3JvdXBzID0gImtlZXAiKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBmaWx0ZXIoc2l0ZSAlaW4lIGMoIkZ0LiBIYW1lciIsICJUeWxlciBDb3ZlIiwgIk1pcmFtaWNoaSIpKQoKZ29sZC5tb2RlbCA9IGxtKGRhdGEgPSBnb2xkX3N0YW5kLCBtZWFuX2N0bWF4IH4gY29sbGVjdGlvbl90ZW1wKQoKZ29sZF9kYXRhID0gZnVsbF9kYXRhICU+JSAKICBncm91cF9ieShzaXRlLCBzZWFzb24pICU+JSAgCiAgbXV0YXRlKG1lYW5fd3QgPSBtZWFuKHdhcm1pbmdfdG9sKSkgJT4lIAogIHNlbGVjdChzaXRlLCBzZWFzb24sIGNvbGxlY3Rpb25fdGVtcCwgbGF0LCBtZWFuX3d0KSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBkaXN0aW5jdCgpICU+JSAgCiAgbXV0YXRlKHByZWRfY3RtYXggPSBwcmVkaWN0KGdvbGQubW9kZWwsIG5ld2RhdGEgPSAuKSwKICAgICAgICAgcHJlZF93dCA9IHByZWRfY3RtYXggLSBjb2xsZWN0aW9uX3RlbXAsCiAgICAgICAgIHd0X2RpZmYgPSBwcmVkX3d0IC0gbWVhbl93dCwKICAgICAgICAgcnVuID0gaSArIDEsCiAgICAgICAgIGdyb3VwID0gImdvbGQiKQoKZ29sZC5tb2RlbCA9IGxtKGRhdGEgPSBnb2xkX2RhdGEsCiAgICAgICAgICAgICAgICB3dF9kaWZmIH4gbGF0KnNlYXNvbikKCmdvbGRfc2xvcGUgPSBlbW1lYW5zOjplbXRyZW5kcyhnb2xkLm1vZGVsLCB2YXIgPSAibGF0Iiwgc3BlY3MgPSAic2Vhc29uIikgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgc2VsZWN0KHNlYXNvbiwgbGF0LnRyZW5kKQoKZ29sZF9wZXJmb3JtYW5jZSA9IGdvbGRfZGF0YSAlPiUgCiAgc2VsZWN0KHNpdGUsIGxhdCwgc2Vhc29uLCB3dF9kaWZmKSAlPiUgIAogIGdyb3VwX2J5KHNpdGUsIHNlYXNvbiwgbGF0KSAlPiUgCiAgc3VtbWFyaXNlKCJtZWFuX2RpZmYiID0gbWVhbih3dF9kaWZmKSwKICAgICAgICAgICAgImFic19kaWZmIiA9IGFicyhtZWFuX2RpZmYpLCAKICAgICAgICAgICAgLmdyb3VwcyA9ICJrZWVwIikgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKCJmbGFnIiA9IGlmX2Vsc2UoYWJzX2RpZmYgPj0gMiwgInllcyIsICJubyIpKSAlPiUgCiAgZmlsdGVyKGZsYWcgPT0gInllcyIpICU+JSAgCiAgZ3JvdXBfYnkoc2Vhc29uKSAlPiUgCiAgc3VtbWFyaXNlKCJhdmdfZGlmZiIgPSBtZWFuKGFic19kaWZmKSwKICAgICAgICAgICAgIm4iID0gbigpLAogICAgICAgICAgICAuZ3JvdXBzID0gImtlZXAiKSAlPiUgIAogIGlubmVyX2pvaW4oZ29sZF9zbG9wZSwgYnkgPSBjKCJzZWFzb24iKSkKCnNjZW5hcmlvXzMgPSBiaW5kX3Jvd3Moc2NlbmFyaW9fMywgZ29sZF9kYXRhKQoKcGVyZm9ybWFuY2VfM19zdW0gPSBwZXJmb3JtYW5jZV8zICU+JSAgCiAgZ3JvdXBfYnkoc2Vhc29uKSAlPiUgIAogIHN1bW1hcmlzZSgiYXZnX2RpZmYiID0gbWVhbihhdmdfZGlmZiksCiAgICAgICAgICAgICJuIiA9IG1lYW4obiksCiAgICAgICAgICAgICJsYXQudHJlbmQiID0gbWVhbihsYXQudHJlbmQpKQoKZ2dwbG90KHNjZW5hcmlvXzMsIGFlcyh4ID0gbGF0LCB5ID0gd3RfZGlmZiwgY29sb3VyID0gZ3JvdXAsIGdyb3VwID0gcnVuKSkgKyAKICBmYWNldF93cmFwKHNlYXNvbn4uLCBucm93ID0gMykgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArIAogIGdlb21fc21vb3RoKGFlcyhjb2xvdXIgPSBncm91cCksIAogICAgICAgICAgICAgIG1ldGhvZCA9ICJsbSIsIHNlID0gRikgKyAKICBnZW9tX3BvaW50KCkgKyAKICBsYWJzKHggPSAiTGF0aXR1ZGUiLCAKICAgICAgIHkgPSAiUHJlZGljdGVkIC0gT2JzZXJ2ZWQgV1QiKSArIAogIHRoZW1lX21hdHRfZmFjZXRzKCkKCmBgYAoKYGBge3J9CmtuaXRyOjprYWJsZShwZXJmb3JtYW5jZV8xLCBjYXB0aW9uID0gIlNjZW5hcmlvIDEiKQoKa25pdHI6OmthYmxlKHBlcmZvcm1hbmNlXzIsIGNhcHRpb24gPSAiU2NlbmFyaW8gMiIpCgprbml0cjo6a2FibGUocGVyZm9ybWFuY2VfM19zdW0sIGNhcHRpb24gPSAiU2NlbmFyaW8gMyIpCgprbml0cjo6a2FibGUoZ29sZF9wZXJmb3JtYW5jZSwgY2FwdGlvbiA9ICJgR29sZGAgU3RhbmRhcmQiKQpgYGAKCmBgYHtyfQpiZXN0ID0gYmluZF9yb3dzKAogIG11dGF0ZShwZXJmb3JtYW5jZV8xLCAic2NlbmFyaW8iID0gIm9uZSIpLAogIG11dGF0ZShwZXJmb3JtYW5jZV8yLCAic2NlbmFyaW8iID0gInR3byIpLAogIG11dGF0ZShwZXJmb3JtYW5jZV8zX3N1bSwgInNjZW5hcmlvIiA9ICJ0aHJlZSIpLAogIG11dGF0ZShnb2xkX3BlcmZvcm1hbmNlLCAic2NlbmFyaW8iID0gImdvbGQiKSkgJT4lIAogIGdyb3VwX2J5KHNlYXNvbikgJT4lICAKICBmaWx0ZXIoYWJzKGxhdC50cmVuZCkgPT0gbWluKGFicyhsYXQudHJlbmQpKSkKICAjZmlsdGVyKGF2Z19kaWZmID09IG1pbihhdmdfZGlmZikpCmBgYAoKCiMjIE5leHQgU3RlcHMKCkFmdGVyIHBoZW5vdHlwaW5nLCBlYWNoIGluZGl2aWR1YWwgd2FzIHByZXNlcnZlZCBpbiA5NSUgZXRoYW5vbC4gSW5kaXZpZHVhbCBETkEgbGlicmFyaWVzIHdpbGwgYmUgcHJlcGFyZWQgdXNpbmcgVHdpc3QgQmlvIDk2LXBsZXggcHJlcCBraXRzLCB0aGVuIHNlcXVlbmNlZCBvbiBhbiBJbGx1bWluYSBOb3ZhU2VxIFggUGx1cy4gVXNpbmcgdGhlIGxvdy1jb3ZlcmFnZSB3aG9sZSBnZW5vbWUgc2VxdWVuY2VzLCB3ZSB3aWxsIGV4YW1pbmUgc2Vhc29uYWwgcGF0dGVybnMgaW4gYWxsZWxlIGZyZXF1ZW5jeSBjaGFuZ2UsIGFuZCBjb21wYXJlIHRoZXNlIGZpbmUgc2NhbGUgdGVtcG9yYWwgcGF0dGVybnMgd2l0aCB0aGUgbGFyZ2VyIGxhdGl0dWRpbmFsIHBhdHRlcm5zIGluIGFsbGVsZSBmcmVxdWVuY3kgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlIHNhbWUgYWxsZWxlcyBkcml2aW5nIHJhcGlkIHNlYXNvbmFsIGFkYXB0YXRpb24gYXJlIGluIHBsYXkgb3ZlciBsYXJnZXIgc3BhdGlhbCAoYW5kIGxvbmdlciB0ZW1wb3JhbCkgc2NhbGVzLgoKIyMgTWlzYy4gRGV0YWlscwoKYGBge3IgdGVtcC1yZWNvcmQtcGxvdCwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9Nn0KZ2dwbG90KHRlbXBfcmVjb3JkLCBhZXMoeCA9IG1pbnV0ZV9wYXNzZWQsIHkgPSB0ZW1wX0MsIGdyb3VwID0gZmFjdG9yKHJ1bikpKSArIAogIGdlb21fYWJsaW5lKHNsb3BlID0gMC4zLCBpbnRlcmNlcHQgPSBtZWFuKHRlbXBfcmVjb3JkW3RlbXBfcmVjb3JkJG1pbnV0ZV9pbnRlcnZhbCA9PSAwLCA4XSkpICsgCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAwLjEsIGludGVyY2VwdCA9IG1lYW4odGVtcF9yZWNvcmRbdGVtcF9yZWNvcmQkbWludXRlX2ludGVydmFsID09IDAsIDhdKSkgKyAKICBnZW9tX2xpbmUobGluZXdpZHRoID0gMC4yLCBhbHBoYSA9IDAuOCkgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBmdWxsX2RhdGEsIAogICAgICAgICAgICAgYWVzKHggPSB0aW1lLCB5ID0gY3RtYXggKyAwLjQpLAogICAgICAgICAgICAgc2l6ZSA9IDIsCiAgICAgICAgICAgICBzaGFwZSA9IDI1KSArCiAgbGFicyh4ID0gIlRpbWUgcGFzc2VkIChtaW51dGVzKSIsCiAgICAgICB5ID0gIlRlbXBlcmF0dXJlIChkZWdyZWVzIEMpIiwKICAgICAgIGZpbGwgPSAiVHJpYWwgTnVtYmVyIikgKyAKICBndWlkZXMoY29sb3VyID0gIm5vbmUiKSArIAogIHRoZW1lX21hdHQoYmFzZV9zaXplID0gMTYpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKYGBgCgpgYGB7ciByYW1wLXJlY29yZC1wbG90LCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQpyYW1wX3JlY29yZDIgPSByYW1wX3JlY29yZCAlPiUgCiAgZ3JvdXBfYnkocnVuLCBtaW51dGVfaW50ZXJ2YWwpICU+JSAKICBzdW1tYXJpc2UobWVhbl9yYW1wID0gbWVhbihyYW1wX3Blcl9taW51dGUpKSAlPiUgCiAgdW5ncm91cCgpCgpnZ3Bsb3QocmFtcF9yZWNvcmQyLCBhZXMoeCA9IG1pbnV0ZV9pbnRlcnZhbCwgeSA9IG1lYW5fcmFtcCkpICsgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMC4zKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuMSkgKyAKICAjZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9oZXgoYmlucyA9IDMwKSArIAogIHlsaW0oMCwgMC4zNSkgKyAKICBsYWJzKHkgPSAiUmFtcCBSYXRlIChkZWcuIEMgLyBtaW4uKSIsCiAgICAgICB4ID0gIlRpbWUgaW50byBydW4gKG1pbnV0ZSkiKSArIAogIHRoZW1lX21hdHQoYmFzZV9zaXplID0gMTYpIApgYGAKCmBgYHtyIHJlcC1jb21wLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9OH0KZnVsbF9kYXRhICU+JSAKICBkcm9wX25hKHJlcGxpY2F0ZSkgJT4lICAKICBnZ3Bsb3QoYWVzKHggPSBmYWN0b3IocmVwbGljYXRlKSwgeSA9IGN0bWF4LCBncm91cCA9IHNpdGUpKSArIAogIGZhY2V0X2dyaWQoc2l0ZX5zZWFzb24sIHNjYWxlcyA9ICJmcmVlX3kiKSArIAogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAwLjEsIGhlaWdodCA9IDApLAogICAgICAgICAgICAgYWxwaGEgPSAwLjQsCiAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTMwIikgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvdXIgPSAiYmxhY2siKSArIAogIGxhYnMoeCA9ICJSZXBsaWNhdGUiLCAKICAgICAgIHkgPSAiQ1RtYXgiKSArIAogIHRoZW1lX21hdHRfZmFjZXRzKCkKYGBgCgpgYGB7ciBudW0tZ2Vucy1wbG90LCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9N30KZ2dwbG90KGhhbGRhbmVzLCBhZXMoeCA9IGxhdCwgeSA9IGdlbnMsIGNvbG91ciA9IHNpdGUsIHNoYXBlID0gc2Vhc29uKSkgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDUpICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzaXRlX2NvbHMpICsgCiAgbGFicyh4ID0gIkxhdGl0dWRlIiwgCiAgICAgICB5ID0gIkdlbmVyYXRpb25zIGJldHdlZW4gXG5jb2xsZWN0aW9ucyIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKGZyb20gPSAwLCB0byA9IDIxLCBieSA9IDUpKSArIAogIHRoZW1lX21hdHQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCmBgYAoKYGBge3IgcmFuay1zaW1zLCBmaWcud2lkdGg9MTgsIGZpZy5oZWlnaHQ9OH0Kb2JzX3JhbmtzID0gZ2dwbG90KGZ1bGxfZGF0YSwgYWVzKHggPSByYW5rKSkgKyAKICBmYWNldF93cmFwKHR1YmV+LikgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGMoMiw0LDYsOCwxMCkpICsgCiAgZ2d0aXRsZSgiT2JzZXJ2YXRpb24iKSArIAogIHRoZW1lX21hdHRfZmFjZXRzKCkKCnNpbV9kYXRhID0gZGF0YS5mcmFtZSgpCmZvcihpIGluIDE6bWF4KGZ1bGxfZGF0YSRydW4pKXsKICByZXBfZGF0YSA9IGRhdGEuZnJhbWUoInR1YmUiID0gc2FtcGxlKGMoMToxMCksIHNpemUgPSAxMCwgcmVwbGFjZSA9IEYpLCAKICAgICAgICAgICAgICAgICAgICAgICAgInJhbmsiID0gYygxOjEwKSwKICAgICAgICAgICAgICAgICAgICAgICAgInJlcCIgPSBpKSAlPiUgCiAgICBhcnJhbmdlKHR1YmUpCiAgCiAgc2ltX2RhdGEgPSBiaW5kX3Jvd3Moc2ltX2RhdGEsIHJlcF9kYXRhKQogIAp9CgpzaW1fcmFua3MgPSBnZ3Bsb3Qoc2ltX2RhdGEsIGFlcyh4ID0gcmFuaykpICsgCiAgZmFjZXRfd3JhcCh0dWJlfi4pICsgCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxKSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBjKDIsNCw2LDgsMTApKSArIAogIGdndGl0bGUoIlNpbXVsYXRpb24iKSArIAogIHRoZW1lX21hdHRfZmFjZXRzKCkKCgpnZ2FycmFuZ2Uob2JzX3JhbmtzLCBzaW1fcmFua3MpCmBgYAoK